In PHP, objects are effectively passed by reference (what’s going on under the hood is a bit more complicated). Meanwhile, parameters to call_user_func()
not passed by reference.
So what happens with a piece of code like this?
class Example {
function RunEvent($event) {
if (isset($this->events[$event])) {
foreach ($this->events[$event] as $k => $v) {
//call_user_func($v, &$this);
// The above line is working code on PHP 5.3.3, but
// throws a parse error on PHP 5.5.3.
call_user_func($v, $this);
}
}
}
}
$e = new Example;
$e->events['example'][] = 'with_ref';
$e->events['example'][] = 'without_ref';
$e->RunEvent('example');
function with_ref(&$e) {
$e->with_ref = true;
}
function without_ref($e) {
$e->without_ref = true;
}
header('Content-Type: text/plain');
print_r($e);
Output:
Example Object
(
[events] => Array
(
[example] => Array
(
[0] => with_ref
[1] => without_ref
)
)
[without_ref] => 1
)
Note: Adding error_reporting(E_ALL);
or error_reporting(-1);
to the top of the file makes no difference. I’m seeing no errors or warnings, and of course php -l
on the command line shows no errors.
I was actually expecting it to work both with and without references in the callback functions. I thought that removing the ampersand before $this
in call_user_func()
would be enough to fix this for the latest version of PHP. Obviously, the version with the reference doesn’t work, but equally it doesn’t throw any linting errors, so it’s hard to track down such situations (which may occur many times in the codebase I’m working with).
I’ve got a practical question here: Is there any way to make the with_ref()
function work? I’d like to modify only the RunEvent()
code, not every single function which uses it (the majority of which do use references).
I’ve also got a curiosity question, as the behaviour I see here makes no sense to me. The opposite would make more sense. What’s actually going on here? It seems startlingly counter-intuitive that a function call without an ampersand can modify the object, while one with the ampersand cannot.