Левая ассоциация левой тройки

В руководстве по PHP я нахожу следующую «записку, внесенную пользователем» в разделе «Операторы».

Заметим, что в php тернарный оператор?: Имеет левую ассоциативность, в отличие от C и C ++, где он имеет правую ассоциативность.

Вы не можете писать такой код (как вы уже привыкли на C / C ++):

<?php $a = 2; echo ( $a == 1 ? 'one' : $a == 2 ? 'two' : $a == 3 ? 'three' : $a == 4 ? 'four' : 'other'); echo "\n"; // prints 'four' 

Я действительно пытаюсь это сделать, и это действительно печатает four . Однако я не мог понять причину этого и все еще чувствую, что он должен печатать то и other .

Может кто-нибудь объяснить, что здесь происходит и почему он печатает «четыре»?

На любом разумном языке тернарный оператор является право-ассоциативным, так что вы ожидаете, что ваш код будет интерпретироваться так:

 $a = 2; echo ($a == 1 ? 'one' : ($a == 2 ? 'two' : ($a == 3 ? 'three' : ($a == 4 ? 'four' : 'other')))); # prints 'two' 

Тем не менее, PHP-тернарный оператор странно лево-ассоциативный, так что ваш код на самом деле эквивалентен этому:

 <?php $a = 2; echo (((($a == 1 ? 'one' : $a == 2) ? 'two' : $a == 3) ? 'three' : $a == 4) ? 'four' : 'other'); # prints 'four' 

Если это еще не ясно, оценка будет выглядеть следующим образом:

 echo ((((FALSE ? 'one' : TRUE) ? 'two' : $a == 3) ? 'three' : $a == 4) ? 'four' : 'other'); echo ((( TRUE ? 'two' : $a == 3) ? 'three' : $a == 4) ? 'four' : 'other'); echo (( 'two' ? 'three' : $a == 4) ? 'four' : 'other'); echo ( 'three' ? 'four' : 'other'); echo 'four'; 

Потому что все ваше выражение оценивается так, как будто оно было (......) ? 'four' : 'other' (......) ? 'four' : 'other' . Поскольку первый элемент, вероятно, является чем-то правдоподобным, он дает вам 'four' . В более простых языках, где ?: Имеет правую ассоциативность, все выражение оценивается так, как будто оно было $a == 1 ? 'one' : (......) $a == 1 ? 'one' : (......) , где, если $a не 1 , вы продолжаете проверять другие вещи.

Если вы добавите круглые скобки, проблема будет решена. Посмотрите на следующий пример:
Без круглых скобок класс всегда D, если метки больше 50, но отлично подходит для меток <= 49.
Чтобы программа работала так, как должна, я добавил круглые скобки. Очень легко узнать, сколько скобок следует вводить, если оно набирается так.

 <?php $marks_obtained = 65; $grade = null; //Use parentheses () otherwise the final grade shown will be wrong. //Excluding the first line, for each additional line, //we add a parenthesis at the beginning of each line and a parenthesis at the end of the statement. echo $grade = $marks_obtained >= 90 && $marks_obtained <= 100 ? "A+" : ($marks_obtained <= 89 && $marks_obtained >= 80 ? "A" : ($marks_obtained <= 79 && $marks_obtained >= 70 ? "B" : ($marks_obtained <= 69 && $marks_obtained >= 60 ? "C" : ($marks_obtained <= 59 && $marks_obtained >= 50 ? "D" : "F")))) ?> 

Я не мог окутать голову в пример:

https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/

Поэтому я приехал сюда, и я все еще не мог обвести вокруг себя голову, поэтому мне пришлось пройти через нее.

У @amadan есть лучший ответ, imo.

Это печатает лошадь, а не поезд.

 // 0 $arg = 'T'; $vehicle = $arg == 'B' ? 'bus' : $arg == 'A' ? 'airplane' : $arg == 'T' ? 'train' : $arg == 'C' ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 1 $vehicle = > FALSE ? 'bus' : $arg == 'A' ? 'airplane' : $arg == 'T' ? 'train' : $arg == 'C' ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 2 $vehicle = FALSE ? 'bus' : > FALSE ? 'airplane' : $arg == 'T' ? 'train' : $arg == 'C' ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 3 $vehicle = > (FALSE? 'bus' : FALSE? 'airplane' : TRUE)? 'train' : $arg == 'C' ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 4 $vehicle = > true ? 'train' : $arg == 'C' ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 5 $vehicle = > ('train' : $arg == 'C') ? 'car' : $arg == 'H' ? 'horse' : 'feet' ; // 6 $vehicle = > (true ? 'car' : $arg == 'H') ? 'horse' : 'feet' ; // 7 $vehicle = > (true) ? 'horse' : 'feet' ; 

Вы можете видеть, какие левые ассоциативные средства на шаге 5, если я правильно понимаю.