以下调用call_user_func_array()是否有效?

时间:2012-07-01 12:36:08

标签: php pass-by-reference php-5.4

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

$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()返回{{ 1}}。

特别是,突出显示的句子似乎暗示了PHP代码中定义的函数没有完成。

以这种方式使用FALSE是否适用于PHP 5.4?

3 个答案:

答案 0 :(得分: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服务器,因此在反序列化params后没有引用值这样的东西):

//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时经常发生。

答案 1 :(得分:1)

如果call_user_func_array()返回false您遇到问题,否则一切都会好起来。

默认情况下,参数不再通过引用传递,但您可以显式执行此操作。 唯一的麻烦可能是你的引用在array_merge()期间丢失了,没有测试过。

答案 2 :(得分:-1)

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

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

这是旧代码:

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);

希望这有帮助!