This is a very edge case in PHP 5.4 regarding passing objects by reference where get this error:
PHP Warning: Parameter 1 to A::foo() expected to be a reference, value given
But only as a compound effect of:
No idea why these things all cause this behaviour or if they should.
Important to note that this effect isn't present in PHP 5.5.
This is the code that will cause the above error, but if you comment the line with COMMENT THIS LINE
the code runs fine (e.g. the object gets passed correctly to the 'foo' function):
class A {
private function foo(&$arg1) {
var_dump('arg1: ', $arg1);
}
}
class B extends A {
public function bar() {
$x = new stdClass();
$x->baz = 'just a value';
$this->callPrivate($x);
}
private function callPrivate($x)
{
$method = new \ReflectionMethod(
'A',
'foo'
);
//* for some reason, the private function needs to have been changed to be 'accessible' for this to work in 5.4
$method->setAccessible(true);
//working 5.4 (* see above) but not in 5.5
$arguments = func_get_args();
//not working in either
$arguments = array($x); // <---- COMMENT THIS LINE TO SEE IT WORK IN PHP 5.4
return $method->invokeArgs($this, $arguments);
}
}
$y = new B();
$y->bar();
I can't see why there would be any difference between the two $arguments arrays since var_dumping them shows the same output. Therefore, I assume it is to do with something lower level like object 'pointers' being different (out of my depth here)?
The other question is if this is a bug in PHP 5.4, 5.5 or both?
Prior to PHP 5.5.6 func_get_args()
took arguments from the VM stack, copied them and returned them in an array. In PHP 5.5.6 an optimization was introduced which avoids these expensive copies in the common case. Instead of copying the zvals only the refcount is increased (by-ref args notwithstanding.)
Normally such a change would have zero effect on user code. But there are a few places in the engine where observable behavior differs based on the refcount of the zval. One such place is by-reference passing:
For the case of a dynamic function call, a zval can be passed by reference either if it is a reference or if it has refcount==1.
Before PHP 5.5.6 the zvals in the array returned by func_get_args()
always had refcount==1, so they went through based on that second case. As of PHP 5.5.6 this is no longer true as by-value zvals will always have refcount>1 and cause an error if you try to pass them by-reference.
Note: The code didn't actually work before PHP 5.5.6 (the by-ref was ignored). It was just an unfortunate coincidence that you didn't get an error telling you so ;)
Update: We decided to revert the change on the 5.5 branch due to the BC break. You will get the old behavior back in PHP 5.5.8 and the new behavior will only be in PHP 5.6.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With