为什么是$ a + ++ $ a == 2?
如果我尝试这个:
$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
笔记:
-
运算符优先级不决定评估的顺序。 运算符优先级只确定expression式
$l + ++$l
被parsing为$l + (++$l)
,但不确定是否首先计算+
运算符的左边或右边的操作数。 如果左操作数首先被计算,结果将是0 + 1,如果右操作数被首先计算,结果将是1 + 1。 -
运算符关联性也不能确定评估顺序。
+
运算符已经离开关联性只会确定$a+$b+$c
被评估为($a+$b)+$c
。 它并不决定单个操作员操作数的评估顺序。
同样重要的是:在关于另一个expression式的错误报告中 ,一个PHP定义的结果,一个PHP开发人员说:“我们不保证评估顺序,就像C没有关系一样。在哪里声明第一个操作数是先评估的?
一个预先增加的运算符“++”发生在它所评估的expression式的其余部分之前。 所以它实际上是:
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。 但是,如果将它作为expression式进行比较,则不等于:
$a++ + ++$a == $a + ++$a
在哪里
$a++ + ++$a == $a-- + --$a
是平等的”。
也可以看看:
- PHP评估顺序(2013年9月,由NikiC提供) ( via )
我在PHP博客文章中的评价命令详细解释了这一点,但这里是基本的想法:
- 运算符优先级和关联性与评估顺序无关。
- PHP不保证评估顺序。 订单可以在PHP版本之间更改,恕不另行通知,也可以根据周围的代码而有所不同。
- “通常”PHP将从左到右评估,除了访问“简单”variables(如
$a
)。 对简单variables的访问将在更复杂的expression式之后执行,无论expression式实际发生的顺序如何。 - 在这种特殊情况下,这意味着
++$a
首先被运行,因为它是一个复杂的expression式,只有$a
的值被提取(在这一点上它已经是1)。 所以有效地你正在求和1 + 1 = 2
。 - 在复杂expression式之后获取简单variables的原因是编译variables(CV)优化。 如果禁用此优化,例如通过使用
@
错误抑制运算符,则所有expression式都将从左到右进行求值,包括简单variables提取。 - 在这种特殊情况下,它意味着
@($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)
的左边expression式时,它已经被增加了,因为++$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
你可能知道我们有两个增量运算符,一个是预增量,另一个是后增量。 预增量在expression式中使用之前增加整数的值,另一方面在expression式中使用之后增加数字的增量值。
假设你有如下的variables$ a和variables$ 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
2
1
在上述情况下, +
运算符的右侧首先被评估(1,1,+)。
这符合interjay的回答 ,即在PHP中不能保证子expression式的评估顺序。 输出可能是 1, 1
的假设是正确的,那些声称输出可能是 1, 2
答案也是正确的。
第一个明显的部分是++
比+
有更高的优先级。
第二部分是PHP引擎不会将第一个操作数的值存储到另一个匿名variables中。 所以$l + ++$l
不是一个qeuivalent
$a = $l; $b = ++$l; return $a + $b;
如前所述,x ++和++ x有所不同。 你可以用这种方式解释它
x++;
分号后递增
和
++x;
增加expression式的评估
所以看起来你的表情是从右到左评估的
echo $l + ++$l;
- 获取$ l: $ l = 0
- 应用++: ++ $ l = 1
- 获得$ l: $ l = 1
- 应用+: $ l + $ l = 1 + 1 = 2
所有的语句都是从右到左执行的。 所以这个值首先增加,比你的variables值= 1,所以1 + 1 = 2