为啥 PHP 在一种情况下允许将文字传递给按引用传递的参数,而在其他情况下不允许?
Posted
技术标签:
【中文标题】为啥 PHP 在一种情况下允许将文字传递给按引用传递的参数,而在其他情况下不允许?【英文标题】:Why does PHP allow passing a literal to a pass-by-reference parameter in one case but not others?为什么 PHP 在一种情况下允许将文字传递给按引用传递的参数,而在其他情况下不允许? 【发布时间】:2016-03-07 10:56:02 【问题描述】:函数array_shift()
通过引用获取一个参数。传递数组文字会导致致命错误:
$ php -r 'var_export(array_shift(array("Test #0"));';echo
致命错误:在第 1 行的命令行代码中只能通过引用传递变量
这如预期的那样失败。但是,当使用 call_user_func_array 调用函数时,PHP 的行为很奇怪:
<?php
var_export(call_user_func_array("array_shift", array(array("Test #1"))));
echo "\n";
$arg1 = array("Test #2");
var_export(call_user_func_array("array_shift", array($arg1)));
echo "\n";
$args = array(array("Test #3"));
var_export(call_user_func_array("array_shift", $args));
echo "\n";
执行时:
$ php test.php
'测试#1'
警告:array_shift() 的参数 1 应为参考,在第 6 行的 /Users/kcc/test.php 中给出值 空
警告:array_shift() 的参数 1 应为参考,在第 10 行的 /Users/kcc/test.php 中给出值 空
call_user_func_array()
不会触发致命错误是可以理解的,但是为什么第一个表单可以正常工作呢?
【问题讨论】:
这里应该是第三个右括号吗?$ php -r 'var_export(array_shift(array("Test #0"));';echo
我对内部结构了解不多,无法解释原因(尽管变量的存在似乎迫使 PHP 返回表达式的值,而不是对它的引用)......但是这已在 PHP7 中“修复”。您将收到所有三个警告。
只是猜测,但由于您使用的是 call_user_func_array,因此在调用 array_shift 时,第二个参数是函数中可用的变量。因此,您正在转移该变量,而不是文字数组值。定义function test($a, $b) $a($b);
的函数,如果在该函数中调用array_shift
,$b
是一个局部变量,而不是像array()
这样的语言结构。因此,您将传递对局部变量的引用。
【参考方案1】:
来自call_user_func_array() 文档:
在 PHP 5.4 之前,
param_arr
中的引用变量通过引用传递给函数,而不管函数是否期望相应的参数通过引用传递。这种形式的调用时按引用传递不会发出弃用通知,但它仍然被弃用,并在 PHP 5.4 中被删除。此外,这不适用于遵循函数签名的内部函数。当函数需要通过引用传递参数时,按值传递会导致警告并让call_user_func()
返回FALSE
(但是,对于引用计数 = 1 的传递值存在异常,例如在文字中,因为这些可以转换为引用而不会产生不良影响——但也不会对该值的写入产生任何影响——但不要依赖这种行为,因为引用计数是一个实现细节,并且这种行为的合理性是有问题)。
(强调我的)
从 PHP 5.4 开始,call_user_func_array()
将其所有参数按值传递给指定的 $callback
,除非上面手动引用中以粗体显示的异常情况。
在Test #1
中,您有一个纯文字,因此您遇到了文档中描述的特殊异常:文字可以转换为引用而没有不必要的副作用(因为它只会在@987654328 时被丢弃@ 完成)。
在Test #2
和Test #3
中,您没有纯文字,并且因为在内部,array_shift
被定义为通过引用获取其参数,call_user_func_array()
会引发上述警告。
在 PHP 7 中,Test #1
是“固定的”,现在可以正确发出警告。
【讨论】:
以上是关于为啥 PHP 在一种情况下允许将文字传递给按引用传递的参数,而在其他情况下不允许?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在一种情况下更改熊猫数据框列中的值很快,而在另一种情况下更改速度很慢?