Bug #54170 [Com]: Object instantion argument not executed when the constructor is missing
| From: | php at mlemoine dot name | 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