Ассоциативность вложенных тернарных операторов в php и java

Итак, я только что прочитал эту запись в блоге и меня смутила часть «тройной оператор является левой ассоциативной», поэтому я запустил пример кода в интерпретаторе:

$arg = 'T';
$vehicle = ( ( $arg == 'B' ) ? 'bus' :
             ( $arg == 'A' ) ? 'airplane' :
             ( $arg == 'T' ) ? 'train' :
             ( $arg == 'C' ) ? 'car' :
             ( $arg == 'H' ) ? 'horse' :
             'feet' );
echo $vehicle;

и действительно, он возвращает horse, что является нелогичным, что было точкой в ​​сообщении в блоге.

Затем из любопытства я попытался «заставить эту работу», переписав ее так, чтобы она соответствовала тому, что, как я думал, нужно «левоассоциативным». Я получил это (форматирование странное, но оно делает его более понятным, по крайней мере, в МОЕЙ голове):

$arg = 'T';
$vehicle = ( ( $arg != 'B' ) ? 
                ( $arg != 'A' ) ? 
                    ( $arg != 'T' ) ? 
                        ( $arg != 'C' ) ? 
                            ( $arg != 'H' ) ? 
                                'feet' :
                            'horse' :
                        'car' :
                    'train' :
                'airplane' :
            'bus'
);
echo $vehicle;

Теперь это работает, как и ожидалось, в том смысле, что любой символ $arg возвращает транспортное средство, которое начинается с этого символа (конечно, в нижнем регистре, но здесь это не важно).

Все еще любопытно, потому что я не понимаю, ПОЧЕМУ первое не работает, я задавался вопросом, не сработает ли второй в правоассоциативном языке, потому что не похоже, что это так. Поэтому я проверил это в интерпретаторе Java. Код здесь для тех, кто хочет попытаться сэкономить несколько секунд.

class Main {
  public static void main(String[] args) {


    Character arg = 'a';
    String vehicle = ( ( arg == 'B' ) ? "bus" :
                        ( arg == 'A' ) ? "airplane" :
                        ( arg == 'T' ) ? "train" :
                        ( arg == 'C' ) ? "car" :
                        ( arg == 'H' ) ? "horse" :
                        "feet" );
    System.out.println(vehicle);
    vehicle = ( ( arg != 'B' ) ? 
                    ( arg != 'A' ) ? 
                        ( arg != 'T' ) ? 
                            ( arg != 'C' ) ? 
                                ( arg != 'H' ) ? 
                                "feet" :
                            "horse" :
                        "car" :
                    "train" :
                "airplane" :
            "bus"
    );
    System.out.println(vehicle);
  }
}

Оба формата работают в java. Итак, что дает в php? Я слышал, что он, по сути, оценивает начальные равенства как окончательные ($arg == 'H'). Но если это так, это означает, что он ведет себя так, как если бы он

$vehicle = ((($arg == 'B') || ($arg == 'A') || ($arg == 'T') ||
             ($arg == 'C') || ($arg == 'H')) ? 'horse' : 'feet');

Это не имеет смысла для меня. Во втором примере php, который я дал, я переместил только место равенства, вложив его в часть if true троичного выражения вместо части if false. Я не понимаю, почему первый метод не работает, если работает второй. Это больше похоже на ошибку, чем на «так должно работать», и я просто неправильно истолковываю вещи, как и должно быть.

ПРИМЕЧАНИЕ. Я знаю, что могу просто обернуть круглые скобки вокруг вещей, чтобы заставить выражение оцениваться так, как я хочу (что, по-видимому, является правоассоциативным). Я не ищу «как заставить это работать», я хочу знать, почему это не работает.


person Miao Liu    schedule 19.02.2016    source источник


Ответы (1)


Левая и правая ассоциативность — это приоритет при объединении нескольких операторов, например. A + B + C.

Для тернарного оператора A ? B : C это имеет смысл только тогда, когда дополнительный тернарный оператор заменяет часть C (или часть A):

A ? B : X ? Y : Z
(A ? B : X) ? Y : Z    <-- left-associative (PHP)
A ? B : (X ? Y : Z)    <-- right-associative (Java, C, C++, C#, Perl)

Если дополнительный тернарный оператор вставлен в середине (заменив B), он может иметь только одно значение:

A ? X ? Y : Z : C
A ? (X ? Y : Z) : C

Вот почему PHP и Java согласны со вторым. Правило левой/правой ассоциативности не применяется.

person Andreas    schedule 19.02.2016
comment
О, кажется, я вижу. Поскольку X не является 0 или чем-то еще, что оценивается как false, окончательной оценкой будет Y. Таким образом, в первом случае $arg=='B' равно false...$arg=='A' равно false...$arg=='T' равно true...train оценивается как true.. .car оценивается как true... конечное значение равно horse? - person Miao Liu; 19.02.2016
comment
@MiaoLiu Ты понял. --- Вывод: левоассоциативный тернарный оператор - очень плохой дизайн. Или подведите итог связанному блогу: PHP — плохой дизайн. Держись подальше. - person Andreas; 19.02.2016
comment
Таким образом, это означает, что в Java сначала оценивается наиболее глубоко вложенный тернар, а затем результат этого выражения используется в качестве одного из возвращаемых значений внешнего выражения. Затем будет оцениваться внешнее выражение, и возвращаемое им значение используется для следующего внешнего оператора и т. д. Правильно? - person Ungeheuer; 22.10.2017
comment
@Ungeheuer Не совсем. Не путайте приоритет и порядок оценки. - person Andreas; 22.10.2017