32

It fires out when I try to call function with argument by reference

function test(&$a) ...

through

call_user_func('test', $b);

5 Answers5

52

call_user_func can only pass parameters by value, not by reference. If you want to pass by reference, you need to call the function directly, or use call_user_func_array, which accepts references (however this may not work in PHP 5.3 and beyond, depending on what part of the manual look at).

Daniel Vandersluis
  • 91,582
  • 23
  • 169
  • 153
  • @Artefacto I left that out originally because the manual states that it's not the case in 5.3, but I've updated my answer. – Daniel Vandersluis Sep 03 '10 at 19:41
  • I would call it directly as I've just had a case where a script works fine on my server with "call_user_func_array" but for my client it throws an error (I'm using 5.3.x and he must be too)...so it seems a bit of touch and go. – KB. Apr 12 '12 at 10:00
  • `ReflectionMethod` is similar: `invoke` does not work, whilst `invokeArgs` does pass the reference. – Tobias K. Oct 22 '18 at 15:03
22

From the manual for call_user_func()

Note that the parameters for call_user_func() are not passed by reference.

So yea, there is your answer. However, there is a way around it, again reading through the manual

call_user_func_array('test', array(&$b));

Should be able to pass it by reference.

Artefacto
  • 96,375
  • 17
  • 202
  • 225
Jim
  • 18,673
  • 5
  • 49
  • 65
  • However, that workaround only works prior to PHP 5.3, according to the manual. – Daniel Vandersluis Sep 03 '10 at 15:31
  • Yea, that is true, so it would probably be best to avoid using that method given it would not be forward compatible. – Jim Sep 03 '10 at 15:35
  • 1
    >Note This will not work for PHP > 5.3.0, so use it with caution. however I just tried on PHP 5.3.3 and it worked without any warning/notices. its seems call_user_func_array hide errors. –  Sep 03 '10 at 15:39
  • 1
    I did but there is another question about using call_user_func_array('test', array(&$b)); with 5.3. manual says it is not allowed but in practice I see the oposit. –  Sep 03 '10 at 15:43
5

I've just had the same problem, changing (in my case):

$result = call_user_func($this->_eventHandler[$handlerName][$i], $this, $event);

to

$result = call_user_func($this->_eventHandler[$handlerName][$i], &$this, &$event);

seem to work just fine in php 5.3.

It's not even a workaround I think, it's just doing what is told :-)

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
rhalff
  • 181
  • 2
  • 4
4

You need to set the variable equal to the result of the function, like so...

$b = call_user_func('test', $b);

and the function should be written as follows...

function test($a) {
    ...
    return $a
}

The other pass by reference work-a-rounds are deprecated.

reubano
  • 5,087
  • 1
  • 42
  • 41
0

You might consider the closure concept with a reference variable tucked into the "use" declaration. For example:

$note = 'before';
$cbl = function( $msg ) use ( &$note )
{
    echo "Inside callable with $note and $msg\n";
    $note = "$msg has been noted";
};
call_user_func( $cbl, 'after' );
echo "$note\n";

Bit of a workaround for your original problem but if you have a function that needs call by reference, you can wrap a callable closure around it, and then execute the closure via call_user_func().

Tel
  • 1