【问题标题】:Post-increment acting weird后增量表现怪异
【发布时间】:2020-01-23 14:32:46
【问题描述】:

我已将问题缩小到此代码

$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. 为什么先执行后增量?这对我来说没有任何意义。传统上,我认为它会在执行表达式中的所有其他操作后增加变量。这也是 PHP 官方网站上所说的。因此,按照我的逻辑(这可能存在极大缺陷),两个表达式都会返回 10。但正如我们所见,POST_INC 是在执行其他任何操作之前执行的。

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

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

【问题讨论】:

    标签: php opcode


    【解决方案1】:

    这里的关键角色是operator precedence,因此,尽管是表达式中的最后一个元素,$a++ 被评估为 first(在 $a 之前)。请注意post increment 中的post 表示对该表达式(变量)的操作后评估和不是对整个表达式(代码行)的评估。

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

    $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
    

    一旦你理解了这一点,这看起来很清楚,但另一方面很好地展示了你可以通过编写你认为你知道它是如何工作的代码而不是它的实际工作原理来轻松地智取自己 :) 所以你要么需要阅读仔细阅读语言文档,以确保您确定知道您编写的代码会做什么,或者在未来的调试会话中为了个人理智而远离编写过于“聪明”的代码:) KISS 原则存在是有原因的。

    【讨论】:

    • 我不明白你的答案和运算符优先级之间的联系。从那个页面我看到'*'是左关联的。这不应该意味着在 $a++ 之前先读取 $a 吗?
    • 这里无关紧要,因为++ 具有更高的优先级。
    • 确实,完全忽略了它。谢谢
    • 确实如此。我猜想了解操作码中发生了什么,在第一个示例中,值(!0)正在递增,但后递增的返回是未递增的值(~2),然后使用乘法 - 所以“3” .对于第二种情况,增量值(!0)用于乘法 - 所以 4。所以我也读错了,这让我又浪费了一个小时,只是为了变得更加困惑。谢谢你的回答。
    猜你喜欢
    • 2021-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2012-02-08
    • 2012-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多