tomsseisums
tomsseisums

Reputation: 13367

PHP anonymous function variable as reference

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

Answers (4)

user2066957
user2066957

Reputation: 21

I used this code

<?php
$myfunction = function &($arg=3)
{
    $arg = $arg * 2;
    return $arg;
};
echo $myfunction();
?>

Worked like a charm. :)

Upvotes: 2

newacct
newacct

Reputation: 122489

This works:

call_user_func_array($function, array(&$variable));

Upvotes: 3

Jon
Jon

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

Undrium
Undrium

Reputation: 2678

What happens if you do this?

call_user_func($function, &$variable);

Upvotes: 1

Related Questions