Reputation: 13367
While working with Laravel framework, more specific - Form macros, I stumbled upon a weird error.
At first, I thought it's something wrong with Laravel, but then I took everything out of context:
<?php
// placeholder function that takes variable as reference
$function = function(&$reference)
{
// append to variable
$reference = $reference . ':' . __METHOD__;
};
// test with straight call
$variable = 'something';
$function($variable);
echo $variable;
// test with call_user_func(), that gets called in Laravels case
$variable = 'something'; // reset
call_user_func($function, $variable);
echo $variable;
While the first call to $function
executes properly, the second try with call_user_func()
, produces (excerpt from Codepad):
Warning: Parameter 1 to {closure}() expected to be a reference, value given
PHP Warning: Parameter 1 to {closure}() expected to be a reference, value given
Fiddle: Codepad @ Viper-7
While writing this, I thought about call_user_func_array()
: fiddle here, but the same error is produced.
Have I got something wrong about references or is this a bug with PHP?
Upvotes: 1
Views: 4929
Reputation: 21
I used this code
<?php
$myfunction = function &($arg=3)
{
$arg = $arg * 2;
return $arg;
};
echo $myfunction();
?>
Worked like a charm. :)
Upvotes: 2
Reputation: 437574
I would call this a bug with PHP, although it's technically a bug with call_user_func
. The documentation does mention this, but perhaps not in a very enlightening way:
Note that the parameters for
call_user_func()
are not passed by reference.
It would be perhaps clearer to say that the arguments to call_user_func()
are not passed by reference (but note that technically it's not necessary to say anything at all; this information is also embedded in the function signature).
In any case, this means is that when call_user_func
finally gets to invoking its target callable, the ZVAL
(PHP engine internal data structure for all types of values) for the argument being passed is not marked as "being-a-reference"; the closure checks this at runtime and complains because its signature says that the argument must be a reference.
In PHP < 5.4.0 it is possible to work around this by using call-time pass by reference:
call_user_func($function, &$variable);
but this produces an E_DEPRECATED
warning because call-time pass by reference is a deprecated feature, and will flat out cause a fatal error in PHP 5.4 because the feature has been removed completely.
Conclusion: there is no good way to use call_user_func
in this manner.
Upvotes: 8
Reputation: 2678
What happens if you do this?
call_user_func($function, &$variable);
Upvotes: 1