Постинкрементный поступок странный - PullRequest
5 голосов
/ 23 января 2020

Я сузил проблему до этого кода

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

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

Вот коды операций VLD для 1-й операции

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

для 2-й операции ($ 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. Итак, по моим логикам c (что может быть невероятно некорректно) оба выражения вернут 10. Но, как мы можем видеть, POST_IN C выполняется раньше всего.

  2. Как мы видим, во время операции MUL для первого случая ~ 2 должен быть результатом для POST_IN C (поэтому значение должно быть 4), что затем умноженное на 3 равно 12. Но во втором случае, где ! 0 по-прежнему равно 3, ~ 2 , по-видимому, также содержит значение 3 , для Причины неизвестны мне, поэтому мы получаем 9 в конце. Почему это происходит?

Я не свободно читаю коды операций, поэтому, возможно, я что-то пропустил, я предполагаю порядок операндов ~ 2, 3 vs ! 0, ~ 2 имеет значение, но я не понимаю, как.

1 Ответ

6 голосов
/ 23 января 2020

Ключевым действующим лицом здесь является приоритет оператора и по этой причине, несмотря на то, что он является последним элементом в выражении, $a++ оценивается first (перед т. Е. $a). Обратите внимание, что post в post increment означает действие после вычисления этого выражения (переменной), а не вычисление всего выражения (строки кода).

В вашем первом случае код такой:

$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++;

Оценка будет go аналогично, с другим значением $a в конец:

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

Это становится ясно, как только вы понимаете это, но, с другой стороны, наглядно демонстрирует, как легко вы можете перехитрить себя, написав код, который, как вы думаете, вы знаете, как он работает, и как он действительно работает :) Поэтому вам нужно либо внимательно прочитать документацию по языку, чтобы точно знать, какой код вы написали, либо просто избегать написания слишком "умного" кода для личной гигиены во время будущей отладки. сеансы :) KISS принцип существует по причине.

...