后增量行为怪异

Chu*_*nga 5 php opcode

我已将问题缩小到此代码

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

$a = 3;
$a = $a * $a++;  
echo $a; //12
Run Code Online (Sandbox Code Playgroud)

这是第一次操作的 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
Run Code Online (Sandbox Code Playgroud)

用于第二次操作 ($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
Run Code Online (Sandbox Code Playgroud)

2个问题:

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

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

我不擅长阅读操作码,所以也许我错过了一些东西,我猜操作数的顺序~2, 3 vs !0, ~2 很重要,但我不明白如何。

Mar*_*ski 6

这里的关键角色是运算符优先级,因此,尽管它是表达式中的最后一个元素,但首先(在 ie 之前)$a++进行评估。请注意in there 表示对该表达式(变量)的评估后操作,而不是对整个表达式(代码行)的评估。$apostpost increment

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

$result = 3 * $a++;
Run Code Online (Sandbox Code Playgroud)

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

     $a = 3
$result = 3 * $a++
        = 3 * 3 
                // $a is 4 now
        = 9
Run Code Online (Sandbox Code Playgroud)

第二种情况不同:

$result = $a * $a++;
Run Code Online (Sandbox Code Playgroud)

因为我们有不止一个对$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
Run Code Online (Sandbox Code Playgroud)

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

$result = $a++ * $a++;
Run Code Online (Sandbox Code Playgroud)

评估将类似,最后具有不同的$a值:

     $a = 3
$result = $a++ * $a++
         // $a is 4 now
        = 3 * $a++
        = 3 * 4
                 // $a is 5 now
        = 12
Run Code Online (Sandbox Code Playgroud)

一旦你理解了这一点,这看起来很清楚,但另一方面很好地证明了你可以通过编写你认为你知道它是如何工作的代码以及它是如何工作的代码来战胜自己是多么容易:) 所以你要么需要仔细阅读语言文档以确保您确切知道您编写的代码会做什么,或者只是为了在未来的调试会话中保持个人理智而避免编写过于“聪明”的代码:) KISS原则的存在是有原因的。