在another question中注意到,在括号中包装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();
我正在尝试在文档中找到显式的任何内容,并明确地解释这里发生的事情。与C ++不同,我不太了解PHP语法及其对语句/表达式的处理,以便自己派生它。
文档中是否隐藏了有关此行为的内容?如果没有,其他人可以解释它而不诉诸假设吗?
我首先发现this EBNF声称代表PHP语法,并试图自己解码我的脚本,但最终放弃了。
然后,using phc
使用以下命令为两个脚本生成两个.dot
变体的foo()
个文件,produced个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
在这两种情况下,结果完全相同:
答案 0 :(得分:32)
此行为可归类为 bug ,因此您绝对不应该依赖它。
在函数调用中抛出消息 not 的(简化)条件如下(参见definition of the opcode ZEND_SEND_VAR_NO_REF
):
让我们更详细地分析这些。
由于附加的括号,PHP不再检测到参数是函数调用。
解析non empty function argument list时,PHP有三种可能性:
expr_without_variable
variable
&
后跟variable
,用于按参考功能删除的通话时间传递)当写get_array()
时,PHP将其视为variable
。
(get_array())
不符合variable
的条件。这是expr_without_variable
。
这最终会影响代码编译的方式,即操作码SEND_VAR_NO_REF
的扩展值将不再包含标志ZEND_ARG_SEND_FUNCTION
,这是在操作码实现中检测到函数调用的方式。
在几个点上,Zend引擎允许使用引用计数1的非引用,其中引用是预期的。这些细节不应该暴露给用户,但遗憾的是它们就在这里。
在您的示例中,您将返回一个未在其他任何位置引用的数组。如果是的话,你仍然会收到消息,即第二点不是真的。
以下非常相似的示例不起作用:
<?php
$a = array();
function get_array() {
return $GLOBALS['a'];
}
return reset((get_array()));
答案 1 :(得分:1)
A)要了解这里发生了什么,需要understand PHP's handling of values/variables and references(PDF,1.2MB)。正如stated throughout the documentation:"references are not pointers";和you can only return variables by reference from a function - 没有别的。
在我看来,这意味着,PHP中的任何函数都将返回引用。但是一些函数(内置于PHP)需要 values / variables 作为参数。现在,如果要嵌套函数调用,则内部函数调用将返回引用,而外部函数调用则需要一个值。这会导致“着名的”E_STRICT错误"Only variables should be passed by reference"。
$fileName = 'example.txt';
$fileExtension = array_pop(explode('.', $fileName));
// will result in Error 2048: Only variables should be passed by reference in…
B)我在PHP-syntax description linked in the question找到了一行。
expr_without_variable = "(" expr ")"
结合documentation中的这句话:“在PHP中,你写的几乎所有内容都是表达式。定义表达式的最简单但最准确的方法是'任何有价值的东西'。”我得出结论,即使(5)
是PHP中的表达式,它也会计算为值为5的整数。
(因为$a = 5
不仅是一个赋值,而且还是一个表达式,它的值为5。)
结论
如果传递对表达式(...)
的引用,则此表达式将返回一个值,然后该值可作为参数传递给外部函数。如果那(我的思路)是真的,那么以下两行应该等效地工作:
// what I've used over years: (spaces only added for readability)
$fileExtension = array_pop( ( explode('.', $fileName) ) );
// vs
$fileExtension = array_pop( $tmp = explode('.', $fileName) );
另见PHP 5.0.5: Fatal error: Only variables can be passed by reference; 13.09.2005