Левая ассоциация левой тройки
В руководстве PHP я нахожу следующую "записку, внесенную пользователем" в разделе "Операторы" .
Обратите внимание, что в php тернарный оператор?: имеет левую ассоциативность, в отличие от C и С++, где он имеет правую ассоциативность.
Вы не можете написать такой код (как вы уже привыкли в C/С++):
<?php
$a = 2;
echo (
$a == 1 ? 'one' :
$a == 2 ? 'two' :
$a == 3 ? 'three' :
$a == 4 ? 'four' : 'other');
echo "\n";
// prints 'four'
Я действительно пробовал, и он действительно печатает four
. Однако я не мог понять причину этого и все еще чувствую, что он должен печатать two
или other
.
Может кто-нибудь объяснить, что здесь происходит и почему он печатает "четыре"?
Ответы
Ответ 1
На любом нормальном языке тернарный оператор является право-ассоциативным, так что вы ожидаете, что ваш код будет интерпретироваться так:
$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';
Ответ 2
Потому что все ваше выражение оценивается так, как будто оно (......) ? 'four' : 'other'
. Поскольку первый элемент, вероятно, является чем-то правдоподобным, он дает вам 'four'
. В более известных языках, где ?:
имеет правую ассоциативность, все выражение оценивается так, как если бы оно было $a == 1 ? 'one' : (......)
, где if $a
не 1
, вы продолжаете проверять другие вещи.
Ответ 3
Если вы добавите круглые скобки, проблема будет решена. Посмотрите на следующий пример:
Без круглых скобок класс всегда 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"))))
?>
Ответ 4
Я не мог окутать голову в пример из:
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, если я правильно понимаю.