哪位 PHP 大神来解答一下优先级和结合性的问题???

2017-12-13 00:13:41 +08:00
 SimbaPeng
php version: 7.0.26
不要问我这个问题有什么意义,谢谢,我只是单纯的想弄清楚 php 的优先级和结合性问题!!!


首先来看一个例子:
>>> $i = 1;
=> 1
>>> $i + $i++;
=> 3

这个很好理解,++优先级高于+, $i++这个表达式的值为 1,虽然是后置递增但$i++在跟$i 相加之前$i 已经完成了自增,所以是 2+1=3。


再看一个例子:
>>> $i = 1;
=> 1
>>> $i + ++$i + $i++;
=> 6

那谁能告诉我这个例子为什么等于 6 ?

按照我的算法:

1.应该先算最右边的$i++, 因为++优先级高于+, 然后++的结合性是从右到左,那么$i++这个表达式的值为 1,然后$i 递增为 2

2.然后算++$i, $i 自增为 3,++$i 表达式的值也为 3

3.然后就是 3 + 3 + 1 = 7

想不通为什么等于 6,求大神解答。



还有个问题:
>>> function foo(){ return 0; }
>>> if (!$a = foo()) { echo 1; }
1⏎

为什么这个例子不会报错?!的优先级不是比=号高么,为什么不是先算!$a???
虽然官方文档说这种操作是允许的,但是这到底算什么啊,feature?
3527 次点击
所在节点    PHP
34 条回复
humpy
2017-12-15 18:09:16 +08:00
至于这个问题,
>>> function foo(){ return 0; }
>>> if (!$a = foo()) { echo 1; }
1⏎

刚才翻了一下源码,似乎是 parser 定义的锅...

Zend/zend_language_parser.y :

| '!' expr { $$ = zend_ast_create_ex(ZEND_AST_UNARY_OP, ZEND_BOOL_NOT, $2); }

「!$a = foo()」这条语句,在语法解析时,会先解析 「$a = foo()」为赋值语句,然后再匹配到 「'!' expr 」

另外,根据这里的语法定义,似乎「~」运算符也有同样的问题...
humpy
2017-12-15 18:10:48 +08:00
@SimbaPeng + 是双目运算符,++ 是单目运算符
SimbaPeng
2017-12-15 18:13:52 +08:00
@humpy 单目运算符有什么问题么,++运算符的优先级高于+,不应该把所有++算完了,再相加起来吗?
humpy
2017-12-15 18:19:58 +08:00
@SimbaPeng 你对单目 /双目运算符的理解有一点偏差

单目运算符的意思就是它只需要一个 oprand 就可以组成一个表达式
双目运算符需要两个 oprand

对于这个表达式「$i + $i++ + ++$i 」,按照语法规则,转换一下就清晰了:

$a = $i++
$b = ++$;

$i + $i++ + ++$i = $i + $a + $b = ($i + $a) + $b
SimbaPeng
2017-12-15 20:32:36 +08:00
@humpy 单目 /双目运算符我知道,你还是没告诉我+号为什么会在第二个++之前运算?你这么说我好迷茫啊,我对优先级的理解是整个表达式中优先级最高的运算符先计算,然后依次计算优先级低的, 同级别按结合性。
比如:

2 + 3 * 2 + 4 / 2

这个表达式不是先算 3 * 2 再算 4 / 2 , 最后再相加吗?

难道是 先算 3 * 2 然后加上 2 , 再算 4 / 2,再相加?

虽然结果都一样

但是优先级到底是什么时候触发的?
humpy
2017-12-15 23:11:21 +08:00
@SimbaPeng 我明白你的意思,但是对编程语言的求值顺序不能按自己的数学习惯套,你把运算符优先级和实际求值顺序搞混了。运算符优先级高不代表它的求值更早,优先级只是说明某些运算符比另一些运算符的「组合能力」更强,是中缀程序语言为了避免歧义的设计,它处于语法设计层面;求值顺序更多是语言实现层面的事,但因为求值过程中可能会产生副作用,为了避免程序员掉坑,所以文档里会写上。

这是顶楼表达式的语法树,求值顺序就是后序遍历的顺序;如果按照你所期望的顺序求值,你觉得应该怎么遍历这颗语法树呢?
SimbaPeng
2017-12-16 04:14:07 +08:00
@humpy 我明白了,一直以为优先级就是求值顺序,原来优先级只是确定操作数的组合方式,并不等于求值顺序,求值顺序是不确定的,副作用的发生时间也是不确定的,由编译器的行为所决定。除了 && || , 等等这些操作符。所以这题应该是没有答案,4,5,6,7 都可以。。。
xiaohanqing
2017-12-16 10:46:06 +08:00
写这样的东西就是坑自己,研究透了有什么用,就算 !$a 先执行也不是报错啊,就是个警告
SimbaPeng
2017-12-16 12:24:13 +08:00
@xiaohanqing 研究透了才知道自己缺的是编译原理方面的知识懂吗?肯定得买本书补补了。写这种东西谁不知道是坑人?关键是自己不去弄懂这些东西就是坑自己,拈轻怕重谁不会?不知道不可怕,可怕的是自己根本不想去知道。

怕是也只有 php 在使用未定义的变量时只是报个 Notice。。。
sagaxu
2017-12-16 22:48:59 +08:00
@SimbaPeng 最好直接去学编译原理,而不是从连个语言规范都没有的 php 中去悟。
SimbaPeng
2017-12-16 23:59:54 +08:00
@sagaxu 谁说我从 php 中去悟了,php 的文档也不会去讲这些东西。我是看到 humpy 道友的解释,加上自己查 c 语言的书关于优先级那一张才弄明白的,只是刚好在 php 的这个问题上发现自己不足而已,php 的语法不规范刚好暴露了我自己对优先级理解的不透彻。没有疑惑就没一探究竟的动力。
cxbig
2017-12-17 09:12:37 +08:00
谁在工作中这样写逻辑的?
探索这些不如多来几个括号解决实际问题,至少别人审阅代码也不用想太多。
SimbaPeng
2017-12-17 18:57:38 +08:00
@cxbig 我在整个帖子中有说过有人会在工作中这样写吗?还是我鼓励你们这样写了?我在这里请教一下语法层面的东西跟我在实际工作中如何去写有关系吗?有冲突吗?我在这里请教为什么,你们却过来告诉我怎么做?答非所问?语文理解能力差?

另外你要是觉得我在这讨论的东西在你眼里不值一提,你大可一笑而过,至少我看到<<C 程序设计语言>>这本书里用了一页纸来说明求值顺序和操作符的副作用。
mingyun
2017-12-17 20:20:19 +08:00
貌似面试喜欢考这些。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/414247

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX