为什么PHP的call_user_func()函数不支持通过引用传递?

时间:2011-06-07 01:10:42

标签: php reference callback language-design

为什么像call_user_func()这样的函数处理函数不支持通过引用传递参数?

docs表示简单的说法“请注意,call_user_func()的参数不会通过引用传递。”我假设PHP开发人员在这种情况下有某种理由禁用该功能。

他们是否面临技术限制?它是语言设计的选择吗?这是怎么发生的?

编辑:

为了澄清这一点,这是一个例子。

<?php

function more(&$var){ $var++; }

$count = 0;
print "The count is $count.\n";

more($count);
print "The count is $count.\n";

call_user_func('more', $count);
print "The count is $count.\n";

// Output:
// The count is 0.
// The count is 1.
// The count is 1.

这是正常运作; call_user_func不会通过引用传递$ count,即使more()将其声明为引用变量。 call_user_func documentation明确表示这是它的工作方式。

我很清楚我可以使用call_user_func_array('more', array(&$count))来获得我需要的效果。

问题是:为什么call_user_func 设计以这种方式工作? passing by reference documentation表示“单独的函数定义足以通过引用正确传递参数。” call_user_func的行为是一个例外。为什么呢?

4 个答案:

答案 0 :(得分:10)

答案深深嵌入了PHP的模型中引用工作的方式 - 不一定是实现,因为这可能会有很大不同,特别是在5.x中版本。我确定你已经听过这些行,它们不像C指针,或C ++引用等等......基本上,当一个变量被赋值或绑定时,它可以以两种方式发生 - 或者通过值(在其中) case将新变量绑定到包含旧值副本的新“box”或引用(在这种情况下,新变量绑定到与旧值相同的值框)。无论我们是在谈论变量,函数参数还是数组中的单元格,都是如此。

当您开始将引用传递给函数时,事情开始变得有点毛茸茸 - 显然,目的是能够修改原始变量。很久以前,调用时传递引用(将引用传递给不期望的函数的能力)已被弃用,因为一个不知道它正在处理引用的函数可能会“意外” '修改输入。将它带到另一个层次,如果该函数调用第二个函数,那本身就不期望引用...那么一切都会断开连接。 可能可以工作,但不能保证,并且可能会破坏某些PHP版本。

这是call_user_func()的用武之地。假设您将引用传递给它(并获取相关的调用时传递引用警告)。然后你的引用绑定到一个新变量 - call_user_func()本身的参数。然后,当调用目标函数时,其参数绑定到您期望的位置。它们根本不受原始参数的约束。它们绑定到call_user_func()声明中的局部变量。 call_user_func_array()也需要谨慎。将引用放在数组单元格中可能会有麻烦 - 因为PHP通过“copy-on-write”语义传递该数组,您无法确定数组是否会在您下面被修改,并且副本将无法获得脱离原始参考文献。

我见过的最有见地的解释(帮助我了解了参考资料)是对PHP“通过引用传递”的评论:

http://ca.php.net/manual/en/language.references.pass.php#99549

基本上逻辑是这样的。您如何编写自己的call_user_func()版本? - 然后解释它如何打破引用,以及当你避免调用时传递引用时它如何失败。换句话说, right 调用函数的方式(指定值,让PHP从函数声明中决定是否传递值或引用)在使用{{1}时不起作用你正在调用两个函数深,第一个按值调用,第二个函数调用第一个函数。

了解这一点,您将对PHP参考资料有更深入的了解(如果可以的话,还有更大的动力去指导)。

答案 1 :(得分:3)

答案 2 :(得分:3)

更新答案:

您可以使用:

call_user_func('more', &$count)

达到与以下相同的效果:

call_user_func_array('more', array(&$count))

出于这个原因,我(毫无根据地)相信call_user_func只是编译时间的捷径。 (即它在编译时被后来替换)

让我对您提出实际问题“为什么call_user_func设计为以这种方式工作?”:

它可能与“为什么有些方法strstr和其他str_replace?”相同,为什么数组函数haystack, needle和字符串函数needle, haystack

这是因为PHP是由许多不同的人设计的,在很长一段时间内,并没有严格的标准。

原始答案:

您必须确保将数组中的变量也设置为引用。

试试这个并记下array(&$t)部分:

function test(&$t) {
    $t++;
    echo '$t is '.$t.' inside function'.PHP_EOL;
}

$t = 0;
echo '$t is '.$t.' in global scope'.PHP_EOL;

test($t);

$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;

call_user_func_array('test', array(&$t));

$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;

应输出:

$t is 0 in global scope
$t is 1 inside function
$t is 2 in global scope
$t is 3 inside function
$t is 4 in global scope

答案 3 :(得分:2)

另一种可能的方式 - 按引用语法保持“正确”的方式:

$data = 'some data';
$func = 'more';
$func($more);

function more(&$data) {
  // Do something with $data here...
}