AW: return /* by reference */ new Foo() in PHP4

php.internals

Matthias Pigulla

20 years ago
> The "return new..." is just a subset of the problem, but not > the only one that is in wide use. For example, this is very common: > > function &getstuff($in) > { > if ($in=='ok') > return new MyObject(); > else > return false; // this is the common line > } > > The "false" obviously is not a variable that can be reference > and it's even not an object, the _technically_ more correct > answer would be "return null;". But both ways of doing it are > are not the "new ..." problem AND throw a notice AND PHP > should be able to silently know what to do. Boxing is an > approach that covers all of the similar problems and I think > it could easily be realizedsince I suppose PHP is already > doing something similar to fix the memory leak problems.
Of course you're right. Seems my view was a little biased from looking at my code only ;). The "return new" issue has the interesting side effect that notices disappear depending on the constructor's implementation details. Many people will agree that your above code should work - when seen from the "conceptual" point of view. It's a nasty side effect that because of the way the PHP4 internals worked, you *had* to use the reference here. Note that the following is yet another way of stating the same: function &getstuff($in) { return ($in == 'ok' ? new MyObject() : null); } The problem is that even if internally temp assignments are used to make it "still work", how to separate the cases where notices are appropriate ("bad code") from those where they are not (because everything was "legal")? [Weak point - others will throw in that it has never been "legal" but "only worked" :)]
> I don't understand the "only on PHP4": Why should PHP4 be > more "advanced" than PHP5 regarding this issue? And more > important: Why should the two versions differ in behaviour in > such a basic point?
With PHP5 object handles, passing around references is really rare. If you ported your code to make use of the new PHP5 features, you probably won't see the whole reference passing-related problems at all (at least not in places where you're only doing correct OO stuff). Your example with PHP5: #!/usr/bin/php5 <?php class Factory { function build($what) { if ($what == 'a') return new Foo(); else return null; } } class Foo { } var_dump($x = Factory::build('a')); var_dump($y = Factory::build('b')); ?> gives: object(Foo)#1 (0) { } NULL Just as one would expect. Matthias

Oliver Grätz

20 years ago
Matthias Pigulla schrieb:
> [...] The "return new" issue has the interesting side > effect that notices disappear depending on the constructor's > implementation details.
Yes. If the language insists on getting on my nerves, well, then it should at least be consistent in doing do ;-)
> Many people will agree that your above code should work - when seen from > the "conceptual" point of view. It's a nasty side effect that because of > the way the PHP4 internals worked, you *had* to use the reference here. > > Note that the following is yet another way of stating the same: > > function &getstuff($in) { > return ($in == 'ok' ? new MyObject() : null); > }
Nice shorter version of the example. All hail quick'n dirty C-style inline-ifs. PHP was never very good at hiding its origin ;-)
> The problem is that even if internally temp assignments are used to make > it "still work", how to separate the cases where notices are appropriate > ("bad code") from those where they are not (because everything was > "legal")?
By being able to switch this particular notice? So one can check all the places where they occur and then decide which are true errors.
> [Weak point - others will throw in that it has never been "legal" but > "only worked" :)]
No, if that hasn't been in the manual in the past then it has been legal since behaviour was "undefined". Now PHP is filling the gaps in the docs and taking a direction where it differs from most other languages so I would call this "willingly breaking working code".
>>I don't understand the "only on PHP4": Why should PHP4 be >>more "advanced" than PHP5 regarding this issue? And more >>important: Why should the two versions differ in behaviour in >>such a basic point? > > With PHP5 object handles, passing around references is really rare. If > you ported your code to make use of the new PHP5 features, you probably > won't see the whole reference passing-related problems at all (at least > not in places where you're only doing correct OO stuff). > > [Example works in PHP5] > Just as one would expect.
Oops. I managed to make the example that simple that it actually worked since it never _needed_ to return a reference. There are more complex cases where sometimes a reference is needed (because the object is already bound into a larger data structure) and sometimes a new object is needed. Then I am stuck with the same annoying problem of being forced to supply dummy containers that you know from PHP4: #!/usr/bin/php5.1 <?php class Factory { private static $predefined=null; function init() { self::$predefined=new Foo(); } function &build($what) { if ($what == 'a') return new Foo(); elseif ($what=='b') return self::$predefined; else return null; } } class Foo {} Factory::init(); var_dump($x = Factory::build('a')); var_dump($y = Factory::build('b')); var_dump($y = Factory::build('c')); throws (since PHP5.1) two of those notices and has to be replaced by #!/usr/bin/php5.1 <?php class Factory { private static $predefined=null; function init() { self::$predefined=new Foo(); } function &build($what) { if ($what == 'a') { $res=new Foo(); return $res; } elseif ($what=='b') return self::$predefined; else { $res=null; return $res; } } } class Foo {} Factory::init(); var_dump($x = Factory::build('a')); var_dump($y = Factory::build('b')); var_dump($y = Factory::build('c')); And a simple "return $res=new Foo();" isn't enough to keep PHP quiet! OLLi ____________ Reverend: "You’re pregnant?" Gabrielle: "Yes. And it's impossible, I’m on the pill... which you probably think is a sin, but it works. It’s a 99.9% effective sin." Reverend: "Maybe it's in that one tenth of a percent that god resides." Gabrielle: "You couldn’t wait to throw that in could you?" [DH 120]