Migrating to PHP 5.3: call_user_func_array()
I've been updating various old pieces of code after our PHP 5.3 upgrade
yesterday afternoon. Today, call_user_func_array()
has
been a recurring theme. Notably, some older WordPress plugins have been causing
issues, as the WordPress plugin API is heavily dependent on
call_user_func_array()
.
Passing non-arrays
Let's first look what happens when we pass a non-array as the second argument to
call_user_func_array()
:
function foo() {
var_dump( func_get_args() );
return 7;
}
var_dump( call_user_func_array( 'foo', 3 ) );
Here's the output in PHP 5.2.17:
array(1) {
[0]=>
int(3)
}
int(7)
And here's PHP 5.3.5:
PHP Warning: call_user_func_array() expects parameter 2 to be array, integer given in /tmp/call_user_func_array.php on line 9
NULL
In my definition a "warning" wouldn't refuse to run a specific command (the
callback) and then continue with program execution, but c'est la vie. One fix is
to typecast as array
, which turns a scalar into a single-element array:
call_user_func_array( 'foo', (array)3 ); // array( 0 => 3 )
However, typecasting would turn an object into an array. An object with three
properties would become an array with three elements, so the callback would get
three arguments (the properties) rather than one argument (the object). The best
solution is to check is_array()
:
call_user_func_array( 'foo', is_array($args) ? $args : array($args) ); // $args, or array( 0 => $args )
Passing by reference
Let's try a callback that expects to get parameters by reference:
function foo( &$input ) {
var_dump( $input );
return 'goodbye';
}
$args = array( 'hello' );
var_dump( call_user_func_array( 'foo', $args ) );
The old PHP 5.2.17 behavior:
string(5) "hello"
string(7) "goodbye"
And now, in PHP 5.3.5:
PHP Warning: Parameter 1 to foo() expected to be a reference, value given in /tmp/call_user_func_array.php on line 9
NULL
Same deal as before: things basically fall of the tracks, with the callback
never executing and the function returning null. One fix is to pass $args
by
reference, and remove the &
from the function definition:
function foo( $input ) {
var_dump( $input );
return 'goodbye';
}
$args = array( 'hello' );
var_dump( call_user_func_array( 'foo', &$args ) );
Or if you don't really require pass by reference (you're not modifying the
input) just remove the &
from the function definition and be done with it.