如果我尝试这个:
$a = 0;
echo $a + ++$a, PHP_EOL;
echo $a;
我得到这个输出:
2
1
演示:http://codepad.org/ncVuJtJu
为什么?
我希望将其作为输出:
1
1
我的理解:
$a = 0; // a === 0
echo $a + ++$a, PHP_EOL; // (0) + (0+1) === 1
echo $a; // a === 1
但为什么这不是输出呢?
所有解释为什么你得到 2 而不是 1 的答案实际上是错误的。根据 PHP 文档,以这种方式混合+
和++
是未定义的行为,因此您可以获得 1 或 2。切换到不同版本的 PHP 可能会改变你得到的结果,它同样有效。
请参阅示例 1,其中说:
// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5
笔记:
运算符优先级不决定计算顺序。运算符优先级仅确定表达式
$l + ++$l
被解析为$l + (++$l)
,但不确定是先计算+
运算符的左操作数还是右操作数。如果首先计算左操作数,则结果为 0+1,如果先计算右操作数,则结果为 1+1。运算符关联性也不决定计算顺序。
+
运算符具有左关联性仅确定$a+$b+$c
被评估为($a+$b)+$c
。它不确定以什么顺序计算单个运算符的操作数。
同样相关的是:在这个关于另一个结果未定义的表达式的错误报告中,一位PHP开发人员说:"我们不保证评估的顺序[...],就像C不保证一样。你能指出文档中任何说明首先计算第一个操作数的地方吗?
预递增运算符"++"发生在它所在的表达式的其余部分计算之前。 所以它实际上是:
echo $l + ++$l; // (1) + (0+1) === 2
a + b
a = 1
b = ++a
:= 2
你为什么期待别的东西?
在 PHP 中:
$a = 0;
$c = $a + ++$a;
运算符优先级可视化:
$c = ($a) + (++$a);
评估顺序可视化:
$a = 0; ($a = 0)
$a = 1; (++$a)
$c = $a + $a (1 + 1);
或写出:
执行求和运算的那一刻,$a
已经是 1,因为已经计算了++$a
。++
运算符先于+
运算符计算。
为了好玩:
$a++ + ++$a
结果也是 2。但是,如果将其作为表达式进行比较,则不相等:
$a++ + ++$a == $a + ++$a
其中作为
$a++ + ++$a == $a-- + --$a
是"平等的"。
<小时 />另请参阅:
- PHP 中的求值顺序 (2013 年 9 月;由 NikiC( (via(
我在 PHP 中的求值顺序博客文章详细解释了这一点,但这是基本思想:
- 运算符优先级和关联性与计算顺序无关。
- PHP 不保证求值顺序。顺序可以在PHP版本之间更改,恕不另行通知,也可能根据周围的代码而有所不同。
- "通常"PHP 将从左到右计算,除了访问"简单"变量(如
$a
(。对简单变量的访问将在更复杂的表达式之后执行,而不管表达式实际出现的顺序如何。 - 在这种特殊情况下,这意味着首先运行
++$a
,因为它是一个复杂的表达式,然后才获取$a
的值(此时它已经是 1(。如此有效地求和1 + 1 = 2
. - 在复杂表达式之后获取简单变量的原因是编译变量 (CV( 优化。如果禁用此优化(例如,通过使用
@
错误抑制运算符(,则会从左到右计算所有表达式,包括简单变量提取。 - 在这种特殊情况下,这意味着
@($a + ++$a)
将导致1
,因为第一个$a
被获取(当时为 0(并在此之后递增。
>++
是优先级较高的运算符,因此首先应用它。
所以现在l = 1.
所以1 + 1 = 2.
当你做你的++$l(前递增(时,它将在你的加法之前完成 ->检查运算符优先级(。
因此,$l
的值将在您添加之前1
:
echo $l + ++$l; // $l => 1 because ++$l is done first
所以你的答案将是2。
但是当你这样做时:
echo $l // you will get your first value which is $l => 1
所以你的答案将是1。
可以通过检查 PHP 如何编译脚本来确认此行为,例如:
$a = 0;
echo $a + ++$a;
编译成以下操作码,然后执行这些操作码:
compiled vars: !0 = $a
line # * op fetch ext return operands
---------------------------------------------------------------------------------
1 0 > ASSIGN !0, 0
1 PRE_INC $1 !0
2 ADD ~2 !0, $1
3 ECHO ~2
4 > RETURN null
这将转换为以下等效脚本:
$a = 0; // ASSIGN
$tmp = ++$a; // PRE_INC
echo $a + $tmp; // ADD, ECHO
结论
当$a
被评估为$a + (++$a)
的左手表情时,它已经被递增了,因为++$a
首先被评估了。
显然,这种行为不应该被依赖;在任何语言中。
查看增量操作手册:
http://www.php.net/manual/en/language.operators.increment.php
或者看这个代码板:http://codepad.org/Y3CnhiLx
<?php
$n = 0;
$m = 0;
echo '++ before:';
echo $n+ ++$n;
echo PHP_EOL;
echo '++ after:';
echo $m+ $m++;
echo PHP_EOL;
echo 'n:'.$n;
echo PHP_EOL;
echo 'm:'.$m;
输出:
++ before:2
++ after:1
n:1
m:1
您可能知道我们有两个增量运算符,一个是前增量,第二个是后增量。前递增在表达式中使用整数之前增加整数的值,另一方面在表达式中使用后递增增加数字的值。
假设您有变量$a和可变$b,如下所示
$a=0;
$b=++$a给出 b=1 的值
而
$b=$a++ 给出值 b=0
代码的输出因 PHP 版本而异,如下所示
4.3.0 - 5.0.5
的输出
1 1
在上述情况下,首先计算+
运算符的左侧 (0, 1, +(。
5.1.0 - 5.5.0alpha4
的输出 阿拉伯数字
1
在上述情况下,首先计算运算符+
右侧 (1, 1, +(。
这与interjay的回答一致,即在PHP中无法保证子表达式的计算顺序。输出可以1, 1
的假设是正确的,声称输出可以1, 2
的答案也是如此。
第一个明显的部分是++
的优先级高于+
。
第二部分是 php 引擎不会将第一个操作数的值存储到另一个匿名变量中。所以$l + ++$l
不是
$a = $l;
$b = ++$l;
return $a + $b;
<</div>
div class="answers"> 如前所述,x++ 和 ++x 是有区别的。你可以这样解释它:
x++;
分号后的增量
和
++x;
表达式求值时的增量
所以似乎你的表情是从右到左评估的
echo $l + ++$l;
- 获取$l:$l = 0
- 应用 ++: ++$l = 1
- 获取$l:$l = 1 应用 +: $l + $l = 1
- + 1 = 2
所有语句从右到左执行。因此,该值首先递增,变量的值是 = 1,因此 1+1=2