Post-增加表现怪异

Post-increment acting weird

我已将问题缩小到这段代码

$a = 3;
$a = 3 * $a++;  
echo $a; //9

$a = 3;
$a = $a * $a++;  
echo $a; //12

这是第一次操作的 VLD 操作码

compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, 3
   3     1        POST_INC                                         ~2      !0
         2        MUL                                              ~3      ~2, 3
         3        ASSIGN                                                   !0, ~3
   4     4        ECHO                                                     !0
   5     5      > RETURN                                                   1

第二次操作($a * $a++)

compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   2     0  E >   ASSIGN                                                   !0, 3
   3     1        POST_INC                                         ~2      !0
         2        MUL                                              ~3      !0, ~2
         3        ASSIGN                                                   !0, ~3
   4     4        ECHO                                                     !0
   5     5      > RETURN                                                   1

2 个问题:

  1. 为什么先执行post增量?这对我来说没有任何意义。传统上,我认为它会在执行完表达式中的所有其他操作后增加变量。 PHP 官方网站上也是这么说的。所以,根据我的逻辑(这可能有难以置信的缺陷),两个表达式都会 return 10。但是正如我们所看到的,POST_INC 是在其他任何事情之前执行的。

  2. 正如我们所见,在MUL操作期间,对于第一种情况,~2应该是结果对于 POST_INC(所以值应该是 4),然后乘以 3 是 12。但是在第二种情况下,!0 仍然是 3,~2 似乎也持有 3 的值,原因我不知道,所以我们最后得到 9。为什么会这样?

我不熟悉操作码,所以也许我错过了一些东西,我在猜测操作数的顺序 ~2, 3 vs !0 , ~2 很重要,但我不明白。

这里的关键角色是 operator precedence,因此,尽管 $a++ 是表达式中的最后一个元素,但 first(之前即$a)。请注意 post increment 中的 post 意味着对该表达式(变量)的 post 评估和对整个表达式(代码行)的 not 评估.

在你的第一种情况下,代码是这样的:

$result = 3 * $a++;

所以用于乘法的 $a 的值是 3 因为它是先读取然后递增的。该表达式中不再使用 $a,因此 $a 的新值并不重要,也不会影响我们,除非再次引用 $a

     $a = 3
$result = 3 * $a++
        = 3 * 3 
                // $a is 4 now
        = 9

第二种情况不同:

$result = $a * $a++;

因为我们对$a的引用不止一处。评价会这样:

     $a = 3
$result = $a * $a++
        = $a * 3  // value of `$a` is 4 after post-increment
                  // evaluation, and this affects us as we 
                  // evaluate $a again
        = 4 * 3
        = 12

为了答案的完整性,让我们再添加一个案例:

$result = $a++ * $a++;

评估将以类似的方式进行,但最后的 $a 值不同:

     $a = 3
$result = $a++ * $a++
         // $a is 4 now
        = 3 * $a++
        = 3 * 4
                 // $a is 5 now
        = 12

一旦你理解了这一点,这看起来就很清楚了,但从另一方面来说,很好地证明了你可以多么容易地超越自己,通过编写你认为你知道它是如何工作的代码而不是它实际上是如何工作的:)所以你要么需要仔细阅读语言文档,以确保您肯定知道您编写的代码会做什么,或者只是为了在以后的调试会话中保持个人理智而避免编写"smart looking"代码: ) KISS 原则存在是有原因的。