为什么像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的行为是一个例外。为什么呢?
答案 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)
见:
http://hakre.wordpress.com/2011/03/09/call_user_func_array-php-5-3-and-passing-by-reference/
Is it possible to pass parameters by reference using call_user_func_array()?
http://bugs.php.net/bug.php?id=17309&edit=1
传递数组中的引用可以正常工作。
答案 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...
}