为了账号安全,请及时绑定邮箱和手机立即绑定

括号会改变函数调用结果的语义

括号会改变函数调用结果的语义

PHP
斯蒂芬大帝 2019-11-30 10:30:01
在另一个问题中,有人指出,将PHP函数调用的结果包装在括号中可以以某种方式将结果转换为完整的表达式,从而可以进行以下工作:<?phperror_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语法及其对语句/表达式的处理知之甚少,无法自行得出。关于此行为,文档中是否隐藏了任何内容?如果不是,那么其他人可以不诉诸假设地解释它吗?更新资料我首先发现该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
查看完整描述

3 回答

?
Qyouu

TA贡献1786条经验 获得超11个赞

此行为可以归为bug,因此您绝对不应依赖它。


不会在函数调用中引发消息的(简化)条件如下(请参阅opcodeZEND_SEND_VAR_NO_REF的定义):


参数不是函数调用(如果是,则通过引用返回),并且

该参数可以是引用,也可以具有引用计数1(如果引用计数为1,则将其转换为引用)。

让我们更详细地分析这些。


第一点是正确的(不是函数调用)

由于附加括号,PHP不再检测到该参数是函数调用。


解析非空函数参数列表时,PHP有三种可能性:


一个 expr_without_variable

一种 variable

(A &后跟一个variable,表示已删除的呼叫时按参考传递功能)

仅在编写get_array()PHP时,会将其视为variable。


(get_array())另一方面没有资格variable。这是一个expr_without_variable。


这最终会影响代码的编译方式,即操作码的扩展值SEND_VAR_NO_REF将不再包含flag ZEND_ARG_SEND_FUNCTION,这是在操作码实现中检测到函数调用的方式。


第二点是正确的(参考计数为1)

在某些情况下,Zend Engine允许引用数为1的非引用(期望引用)。这些细节不应暴露给用户,但是不幸的是它们在这里。


在您的示例中,您将返回未从其他任何地方引用的数组。如果是这样,您仍然会收到消息,即第二点将不成立。


因此,以下非常相似的示例不起作用:


<?php


$a = array();

function get_array() {

   return $GLOBALS['a'];

}


return reset((get_array()));


查看完整回答
反对 回复 2019-11-30
?
忽然笑

TA贡献1806条经验 获得超5个赞

A)要了解这里发生的情况,需要了解PHP对值/变量和引用的处理(PDF,1.2MB)。正如整个文档中所述:“引用不是指针”;而且您只能通过函数的引用返回变量 -别无其他。


在我看来,这意味着PHP中的任何函数都将返回reference。但是某些函数(用PHP内置)需要值/变量作为参数。现在,如果要嵌套函数调用,则内部的将返回一个引用,而外部的将返回一个值。这导致“著名的” E_STRICT错误“仅应通过引用传递变量”。


$fileName = 'example.txt';

$fileExtension = array_pop(explode('.', $fileName));

// will result in Error 2048: Only variables should be passed by reference in…

B)我在问题中链接的PHP语法描述中找到了一行。


expr_without_variable = "(" expr ")"

结合文档中的这句话:“在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:致命错误:只能通过引用传递变量;否则,不能进行引用。2005年9月13日


查看完整回答
反对 回复 2019-11-30
?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

那么这篇文章是高度投机的。在没有文档的情况下(我已经搜索了一个多小时,并且知道如何使用搜索引擎),这是我能提供的最好的服务。我的想法是,通常以SO-wiki条目的形式为该行为创建一个文档。

查看完整回答
反对 回复 2019-11-30
  • 3 回答
  • 0 关注
  • 407 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号