具有递增的非直观表达式评估

Dan*_*iel 46 php increment opcode

对于以下代码

<?php

$a=1;   $b=$a++;              var_dump($b);
$a=1;   $b=$a+$a++;           var_dump($b);
$a=1;   $b=$a+$a+$a++;        var_dump($b);
$a=1;   $b=$a+$a+$a+$a++;     var_dump($b);
$a=1;   $b=$a+$a+$a+$a+$a++;  var_dump($b);
Run Code Online (Sandbox Code Playgroud)

我得到了这个结果:

int(1)
int(3)
int(3)
int(4)
int(5)
Run Code Online (Sandbox Code Playgroud)

我预计1,2,3,4,5而不是1,3,3,4,5.$a=1; $b=$a+$a++;我们获得后为什么$b=3

PHP 7.1.5-1 + deb.sury.org~xenial + 1(cli)(建于2017年5月11日14:07:52)(NTS)

axi*_*iac 30

$a=1;   $b=$a+$a++;           var_dump($b);            // int(3)
Run Code Online (Sandbox Code Playgroud)

假设上面的表达式从左到右进行如下评估(临时变量$u$v在说明中为了清楚起见):

 $a = 1;
 $u = $a;              //    ($a)   the LHS operand of `+`
 $v = $a;              //  \ ($a++) the RHS operand of `+`
 $a ++;                //  /
 $b = $u + $v;         // 2 (1+1)
Run Code Online (Sandbox Code Playgroud)

无法保证子表达式按指定顺序进行评估.PHP运营商的文档页面说明(重点是我的):

运算符优先级和关联性仅确定表达式的分组方式,它们不指定评估顺序.PHP(在一般情况下)不指定评估表达式的顺序,并且应该避免采用特定评估顺序的代码,因为行为可以在PHP版本之间或根据周围代码进行更改.

只有偶然,PHP为其他表达式计算的值与您假设的值匹配.当使用不同版本的PHP解释器执行代码时,它们的值可能不同.

  • 不.[逻辑AND(`&&`)]的操作数(http://php.net/manual/en/language.operators.logical.php)和[逻辑OR(`||`)](http: //php.net/manual/en/language.operators.logical.php)运算符总是从左到右进行评估,因为评估是"短路的".这意味着当计算的操作数确定最终结果时,表达式的计算将停止.这意味着`isset($ a)`总是首先被评估,如果它返回`FALSE`,那么`doStuffWith($ a)`不被评估,因为它的值不能改变表达式的值.请参见链接页面上的"示例#1". (5认同)
  • @Bergi - 我不知道如何实现PHP VM,但堆栈机器的一个常见优化是,如果你有一系列操作,就像`a op1(b op2 c)`那么它编译为`push a; 推b; 推c; OP2; op1;`它需要在堆栈上有3个值的空间,但是如果你改为将它转换为`(b op2 c)op1r a`(其中`op1r`是`op1`的变体,它以相反的顺序接受它的参数)编译成'推b; 推c; OP2; 推 op1r`,它只需要堆栈上2个值的空间. (3认同)

dec*_*eze 23

PHP(在一般情况下)不指定表达式的评估顺序,应该避免采用特定评估顺序的代码[...]

http://php.net/manual/en/language.operators.precedence.php

您得到不同结果的原因是有时首先评估右操作数,有时是左操作数.PHP不保证操作的顺序,所以没有正确的答案,这完全属于未定义的行为类别.

  • 不,括号指定分组,即将针对哪些表达式评估哪些表达式.除非这些表达式是嵌套的,否则它们仍然不指定评估顺序.即`$ a +($ a + $ a ++)`保证首先评估`$ a + $ a ++',但它不能保证首先评估哪个操作数.并且`$ a +($ a ++)`与`$ a +(((($ a ++))))`相同,并且简单地被引擎简化为等价的`$ a + $ a ++'; 即它对单个操作数没有任何影响. (3认同)

Sal*_*ter 10

根据PHP手册

运算符优先级和关联性仅确定表达式的分组方式,它们不指定评估顺序.PHP(在一般情况下)不指定评估表达式的顺序,并且应该避免采用特定评估顺序的代码,因为行为可以在PHP版本之间或根据周围代码进行更改.

<?php
$a = 1;
echo $a + $a++; // may print either 2 or 3

$i = 1;
$array[$i] = $i++; // may set either index 1 or 2
?>
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我已经预料到其他线条会$b=$a+$a+$a++;遵循相同的模式,但似乎没有.