Lig*_*ica 52 php php-internals
在另一个问题中指出,在括号中包装PHP函数调用的结果可以某种方式将结果转换为完全成熟的表达式,以便以下工作:
<?php
error_reporting(E_ALL | E_STRICT);
function get_array() {
return array();
}
function foo() {
// return reset(get_array());
// ^ error: "Only variables should be passed by reference"
return reset((get_array()));
// ^ OK
}
foo();
Run Code Online (Sandbox Code Playgroud)
我试图在文档中找到任何内容,以明确无误地解释这里发生的事情.与C++不同,我不太了解PHP语法及其语句/表达式的处理方法,以便自己派生它.
有关此行为的文档中是否隐藏了任何内容?如果没有,其他人可以解释它而不诉诸假设吗?
我首先发现这个EBNF声称代表PHP语法,并试图自己解码我的脚本,但最终放弃了.
然后,使用phc生成.dot两个foo()变体的文件,我使用以下命令为两个脚本生成 AST图像:
$ yum install phc graphviz
$ phc --dump-ast-dot test1.php > test1.dot
$ dot -Tpng test1.dot > test1.png
$ phc --dump-ast-dot test2.php > test2.dot
$ dot -Tpng test2.dot > test2.png
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,结果完全相同:
Nik*_*kiC 32
此行为可能被归类为错误,因此您绝对不应该依赖它.
不在函数调用上抛出的消息的(简化)条件如下(参见操作码ZEND_SEND_VAR_NO_REF的定义):
让我们更详细地分析这些.
由于附加括号,PHP不再检测到参数是函数调用.
解析非空函数参数列表时,PHP有三种可能性:
expr_without_variablevariable&后跟a variable,对于删除的呼叫时间传递参考功能)When writing just get_array() PHP sees this as a variable.
(get_array()) on the other hand does not qualify as a variable. It is an expr_without_variable.
This ultimately affects the way the code compiles, namely the extended value of the opcode SEND_VAR_NO_REF will no longer include the flag ZEND_ARG_SEND_FUNCTION, which is the way the function call is detected in the opcode implementation.
At several points, the Zend Engine allows non-references with reference count 1 where references are expected. These details should not be exposed to the user, but unfortunately they are here.
In your example you're returning an array that's not referenced from anywhere else. If it were, you would still get the message, i.e. this second point would not be true.
所以下面非常相似的例子不起作用:
<?php
$a = array();
function get_array() {
return $GLOBALS['a'];
}
return reset((get_array()));
Run Code Online (Sandbox Code Playgroud)