Почему $ a + ++ $ a == 2? - PullRequest
       30

Почему $ a + ++ $ a == 2?

65 голосов
/ 15 марта 2012

Если я попробую это:

$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

Но почему это не выход?

Ответы [ 13 ]

112 голосов
/ 15 марта 2012

Все ответы, объясняющие, почему вы получаете 2, а не 1, на самом деле неверны. Согласно документации PHP, смешивание + и ++ таким образом является неопределенным поведением, поэтому вы можете получить либо 1, либо 2. Переключение на другую версию PHP может изменить полученный результат, и это будет так же, как действительный.

См. пример 1 , в котором говорится:

// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5

Примечания:

  1. Приоритет оператора не определяет порядок оценки. Приоритет оператора определяет только то, что выражение $l + ++$l анализируется как $l + (++$l), но не определяет, оценивается ли в первую очередь левый или правый операнд оператора +. Если левый операнд вычисляется первым, результат будет 0 + 1, а если правый операнд вычисляется первым, результат будет 1 + 1.

  2. Оператор ассоциативности также не определяет порядок оценки. То, что оператор + оставил ассоциативность, только определяет, что $a+$b+$c оценивается как ($a+$b)+$c. Он не определяет, в каком порядке вычисляются операнды одного оператора.

Также актуально: В отчете об ошибке , касающемся другого выражения с неопределенными результатами, разработчик PHP говорит: «Мы не даем никаких гарантий относительно порядка оценки [...], так же как C не . Можете ли вы указать на любое место в документации, где указано, что первый операнд вычисляется первым? "

66 голосов
/ 15 марта 2012

Оператор преинкремента "++" выполняется перед тем, как вычисляется остальная часть выражения, в котором он находится. Так оно и есть на самом деле:

echo $l + ++$l; // (1) + (0+1) === 2
24 голосов
/ 15 марта 2012
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.Однако, если вы сравните его как выражение, оно не будет равно:

$a++ + ++$a == $a + ++$a

Где, как

$a++ + ++$a == $a-- + --$a 

равно "равно".


См. Также:

7 голосов
/ 03 октября 2013

My Порядок оценки в PHP В блоге объясняется это подробно, но вот основная идея:

  • Приоритет оператора и ассоциативность не имеют никакого отношения кделать с порядком оценки.
  • PHP не гарантирует порядок оценки.Порядок может меняться между версиями PHP без предварительного уведомления, а также может отличаться в зависимости от окружающего кода.
  • «Обычно» PHP будет вычислять слева направо, за исключением доступа к «простым» переменным (например,$a).Доступ к простым переменным будет выполняться после более сложных выражений, независимо от того, в каком порядке они на самом деле встречаются.
  • В данном конкретном случае это означает, что ++$a запускается первым, потому что этосложное выражение, и только тогда извлекается значение $a (на данный момент оно равно 1).Так эффективно вы суммируете 1 + 1 = 2.
  • Причина, по которой простые переменные выбираются после сложных выражений, - это оптимизация скомпилированных переменных (CV).Если вы отключите эту оптимизацию, например, с помощью оператора подавления ошибок @, все выражения будут оцениваться слева направо, включая простые выборки переменных.
  • В данном конкретном случае это означает, что @($a + ++$a) будетрезультат 1, потому что сначала $a выбирается (0 в то время) и увеличивается только после этого.
6 голосов
/ 15 марта 2012

++ является оператором с более высоким приоритетом, поэтому он применяется первым.

Так что теперь l = 1.

Итак 1 + 1 = 2.

3 голосов
/ 15 марта 2012

Когда вы делаете ваш ++ $ l (preincrement), это будет сделано до вашего добавления -> проверка приоритета оператора ).

Итак, значение $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.

2 голосов
/ 27 ноября 2012

Это поведение можно подтвердить, проверив, как 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), оно уже былоувеличен, потому что ++$a был оценен первым.

Очевидно, что на это поведение не следует полагаться ;на любом языке по этому вопросу.

1 голос
/ 08 февраля 2013

Вывод вашего кода зависит от версии PHP , как показано здесь

Вывод для 4.3.0 - 5.0.5
1
1

В вышеприведенном случае сначала выполняется оценка левой стороны оператора + (0, 1, +).

Вывод для 5.1.0 - 5.5.0alpha4
2
1

В приведенном выше случае правая часть оператора + вычисляется первой (1, 1, +).

Это соответствует interjay's answer о том, что в PHP нет гарантии порядка порядка подвыражений.Предположение, что вывод может быть 1, 1, является правильным, поэтому ответы, которые утверждают, что вывод может быть 1, 2.

1 голос
/ 15 марта 2012

Как вы, возможно, знаете, у нас есть два оператора инкремента, один из которых является преинкрементным, а второй - постинкрементным. Предварительное увеличение увеличивает значение целого числа перед его использованием в выражении, с другой стороны, после увеличения значения значения числа после его использования в выражении.

предположим, что у вас есть переменная $ a и переменная $ b, как показано ниже

$ а = 0;

$ b = ++ $ a дает значение b = 1

, а

$ b = $ a ++ дает значение b = 0

1 голос
/ 15 марта 2012

Проверьте руководство по приращению:

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
...