0

我有几个库使用类似于以下代码的代码。

$args = array_merge(array(&$target, $context), $args);
$result = call_user_func_array($callback, $args);

两种情况下的代码都不同,但我展示的代码基本上是完成的。该 $callback函数使用以下签名:

function callback(&$target, $context);

库文件和第三方代码(称为插件或扩展)都采用该函数签名,这意味着没有一个扩展将回调定义为,例如 function my_extension_loader_callback($target, $context).

令我困惑的是call_user_func_array()文档中的以下句子。

在 PHP 5.4 之前,param_arr 中的引用变量通过引用传递给函数,而不管函数是否期望相应参数通过引用传递。这种形式的调用时按引用传递不会发出弃用通知,但它仍然被弃用,并已在 PHP 5.4 中删除。此外,这不适用于遵循函数签名的内部函数。当函数需要通过引用传递参数时,按值传递会导致警告并call_user_func()返回FALSE

特别是,突出显示的句子似乎表明 PHP 代码中定义的函数没有这样做。

以这种方式使用call_user_func_array()在 PHP 5.4 中有效吗?

4

3 回答 3

3

使用call_user_func_array时,在较新版本的 PHP 中,当函数需要引用时按值传递被视为错误。

这是 PHP 5.3.3 之前的有效 PHP 代码:

//first param is pass by reference:
my_function(&$strName){
}

//passing by value, not by reference, is now incorrect if passing by reference is expected:
call_user_func_array("my_function", array($strSomething));

//correct usage
call_user_func_array("my_function", array(&$strSomething));

上面的值传递不再可能没有警告(我的项目也设置为在任何类型的错误(通知、警告等)上抛出异常。)所以我必须解决这个问题。

解决方案 我遇到了这个问题,这就是我解决它的方法(我有一个小型 RPC 服务器,所以在反序列化参数后没有引用值之类的东西):

//generic utility function for this kind of situations
function &array_make_references(&$arrSomething)
{ 
    $arrAllValuesReferencesToOriginalValues=array();
    foreach($arrSomething as $mxKey=>&$mxValue)
        $arrAllValuesReferencesToOriginalValues[$mxKey]=&$mxValue;
    return $arrAllValuesReferencesToOriginalValues;
}

虽然$strSomething不是通过引用传递,array_make_references但会使其成为对自身的引用:

call_user_func_array("my_function", array_make_references(array($strSomething)));

我认为 PHP 人员正在考虑帮助人们捕获错误调用的函数(一个很好隐藏的陷阱),这在通过call_user_func_array.

于 2012-07-01T13:26:39.673 回答
1

如果call_user_func_array()退货false你有问题,否则一切都会好起来的。

默认情况下,参数不再通过引用传递,但您可以明确地进行。唯一的麻烦可能是您的参考在 期间丢失array_merge(),尚未测试。

于 2012-07-01T12:47:58.223 回答
-1

当有几个站点使用call_user_func_array通过引用传递的参数时,我在升级到 PHP5.4 时发现了同样的问题。

我所做的解决方法非常简单,包括call_user_func_array使用 eval() 将其自身替换为完整的函数调用。这不是最优雅的解决方案,但它符合我的目的:)

这是旧代码:

call_user_func_array($target, &$arguments);

我替换为:

$my_arguments = '';
for ($i=0; $i<count($arguments); $i++) {
    if ($i > 0) { $my_arguments.= ", "; }
    $my_arguments.= "\$arguments[$i]";
}
$evalthis = " $target ( $my_arguments );";
eval($evalthis);

希望这可以帮助!

于 2014-07-05T20:00:16.690 回答