我有几个库使用类似于下面的代码。
$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?
答案 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);
希望这有帮助!