【问题标题】:Does the following call to call_user_func_array() work?以下对 call_user_func_array() 的调用是否有效?
【发布时间】:2012-07-01 12:36:08
【问题描述】:

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

$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 代码中定义的函数没有这样做。

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      如果call_user_func_array() 返回false 你有问题,否则一切都应该没问题。

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

      【讨论】:

      • call_user_func_array() 返回被调用函数返回的任何内容。如果被调用的函数也返回false作为一个有效的返回值,那么依赖这个返回值进行错误检测并不是一个好的做法。
      【解决方案3】:

      当有多个站点使用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);
      

      希望这会有所帮助!

      【讨论】:

      • 我没有否决这个问题,但eval() 是魔鬼。它不应该被使用。
      猜你喜欢
      • 2021-04-18
      • 1970-01-01
      • 2013-08-01
      • 2015-10-18
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      • 2014-03-15
      • 2016-06-06
      相关资源
      最近更新 更多