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

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

$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 

Но почему это не так?

Все ответы, объясняющие, почему вы получаете 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 говорит: «Мы не гарантируем порядок оценки […], так же, как и нет. Можете ли вы указать на любое место на где указано, что первый операнд оценивается первым? "

Оператор preincrement «++» имеет место перед остальной частью выражения, которое он оценивает. Так это на самом деле:

 echo $l + ++$l; // (1) + (0+1) === 2 
 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 

равно".


Смотрите также:

  • Порядок оценки в PHP (сентябрь 2013 г., NikiC) ( через )

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

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

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

Итак, теперь l = 1.

Итак, 1 + 1 = 2.

Когда вы выполняете свой ++ $ 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.

Такое поведение можно подтвердить, проверив, как 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 .

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

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

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 

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

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

$ А = 0;

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

в то время как

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

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

Выход для 4.3.0 – 5.0.5
1
1

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

Выход для 5.1.0 – 5.5.0alpha4
2
1

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

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

Первая очевидная часть заключается в том, что ++ имеет более высокий приоритет, чем + .

Вторая часть заключается в том, что php-движок не сохраняет значение из первого операнда в другую анонимную переменную. Таким образом, $l + ++$l не является qeuivalent для

 $a = $l; $b = ++$l; return $a + $b; 

Как упоминалось ранее, существует разница в x ++ и ++ x. Вы можете интерпретировать это так, как это

 x++; 

приращения после точки с запятой

а также

 ++x; 

приращения при оценке выражения

Таким образом, кажется, что ваше выражение оценивается справа налево

 echo $l + ++$l; 
  1. Получить $ l: $ l = 0
  2. Применить ++: ++ $ l = 1
  3. Получить $ l: $ l = 1
  4. Применить +: $ l + $ l = 1 + 1 = 2

Все утверждения выполняются справа налево. Таким образом, значение сначала увеличивается, чем значение вашей переменной = 1, поэтому 1 + 1 = 2