Bug #54170 [Com]: Object instantion argument not executed when the constructor is missing

From: Date: Thu, 31 Oct 2013 20:18:23 +0000
Subject: Bug #54170 [Com]: Object instantion argument not executed when the constructor is missing
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-182532@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=54170&edit=1 ID: 54170 Comment by: php at mlemoine dot name Reported by: martijn at site-to-make dot nl Summary: Object instantion argument not executed when the constructor is missing Status: Not a bug Type: Bug Package: Scripting Engine problem Operating System: Debian 6.0 PHP Version: 5.3.5 Block user comment: N Private report: N New Comment: Well, the problem is not occurring only if the arguments of constructor are supposed to be throwing a Fatal Error. I think the problem is even bigger if the arguments of the constructor are valid and expected to provide some kind of side-effect. If the class name is provided via a variable, you end up with a very nasty corner case where your side-effects are sometimes executed, and sometimes not. Please refer to https://bugs.php.net/bug.php?id=65930 (Marked as Duplicate of this bug, but in my opinion with a much higher severity). This is not okay to optimize this away. With PHP the only other case where the arguments of a function call are not evaluated is when the function does not exists and then a Fatal Error is thrown. This doesn't matter much since it won't have any effect unless the side-effect were supposed to have an impact outside of PHP (e.g. creating a file), but in any case, this could be seen as "You're function is resolved first, then the arguments are evaluated, then the function is called with the computed value of the arguments. Since the function doesn't exist, an error is thrown and your arguments never get evaluated.". Dealing with unresolved side-effects in this case is part of error management, but at least, you have an active and immediate way of telling that something could have gone wrong. In the case of a non-existing constructor, your side effect are not resolved, but unless you go digging within the Reflection API, nothing, not even a strict or a notice is going to tell that something could have gone wrong regarding your side-effects and your object is still going to be built as nothing wrong happened. This is a silent fail which is definitely WRONG and a recipe for debugging headache. In this case, I think the best way to go would be to replace the "no constructor but a weird behaviour" implementation by a "default constructor with an empty body if none is defined or inherited with no "Rasmus unoptimization". This is much saner and the least surprising behavior. In the mean time, the right behavior is not to use the Reflection API, but to make sure the arguments evaluation would have no side-effects. In this case: $tmp_arg_1 = new ThisIsANotExistingClass(); new A($tmp_arg_1); Previous Comments: ------------------------------------------------------------------------ [2013-10-22 12:06:17] bwoebi@php.net Related to #65930 ------------------------------------------------------------------------ [2013-09-28 15:05:59] MonYeaTea at ist dot mit dot edu Well, the problem is that PHP does not break down here. It's okay to optimize here, and as Rasmus named it first that there is an evaluation optimization with the new operator, let's start to name that optimization after him: Rasmus evaluation. This Rasmus evaluation is also the case with any other non-existent function or method. The arguments to these aren't evaluated either. However - and this seems to be missing here - these function/method calls are producing fatal errors - the missing constructor function doesn't. The workaround (in your case) is to not use the new operator but to use ReflectionClass::newInstance(): <?php class A {} (new ReflectionClass('A'))->newInstance(new ThisIsANotExistingClass()); However there is a caveat: With this workaround you do not profit from the Rasmus evaluation any longer. The fatal error will be thrown *after* the arguments have been evaluated. This is because of the layer of indirection the ReflectionClass adds here. Hope this helps until PHP is fixed and throws a fatal error when a non-existent constructor is called in the future. Then you can profit safely from Rasmus evaluation again. ------------------------------------------------------------------------ [2011-03-05 19:47:52] info at liefcoden dot nl Well then, let me tell my customers their applications might break down because of this "feature". Thanks very much. ------------------------------------------------------------------------ [2011-03-05 19:41:41] rasmus@php.net Without a constructor the arguments to the new call mean nothing and are optimized away. The object is still created: class A { } $b = new A(new ThisIsANotExistingClass()); var_dump($b); outputs: object(A)#1 (0) { } ------------------------------------------------------------------------ [2011-03-05 19:33:32] info at liefcoden dot nl As an addition (because it is probably the same problem): class B { public function __construct( ) { echo 'B::__construct();'; } } class A { } new A( new B( ) ); The above code prints nothing as well. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at https://bugs.php.net/bug.php?id=54170 -- Edit this bug report at https://bugs.php.net/bug.php?id=54170&edit=1

« previous php.bugs (#182532) next »