Как понять логику?

85
16 марта 2022, 21:30

Читал статью «почему не любят php». И там был пример, приводился этот код:

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

У меня вопрос, Почему результат будет horse, а не train? Что это за логика языка? Я уже две книги заказал по php, а тут такие логические проблемы, да и ещё их не исправляют.

Answer 1

Всё довольно просто: в php свой, довольно специфический, порядок выполнения тернарного оператора: конструкция

true ? 1 : true ? 2 : 3

в большинстве языков (скажем, в JS, Java, C++, Python, Ruby, Perl) будет выполняться в том же порядке, что и

true ? 1 : (true ? 2 : 3)

в php же порядок выполнения будет соответствовать

(true ? 1 : true) ? 2 : 3

Это непривычно и не слишком удобно; мануал не описывает какой-то специальной логики, разве что можно понимать это как "побольше ассоциативности слева направо" (как с арифметическими операторами: 1 / 2 / 3 – то же, что (1 / 2) / 3). Мануал упоминает, что лучше на порядок выполнения вообще не полагаться, и что он может быть изменён со сменой версии языка:

PHP does not (in the general case) specify in which order an expression is evaluated and code that assumes a specific order of evaluation should be avoided, because the behavior can change between versions of PHP or depending on the surrounding code.

но из соображений обратной совместимости представляется маловероятным, что это изменят. См также deprecation в 7.4

Answer 2

Не знаю для чего используется такая ужасная конструкция, даже на привычном if/else, все выглядит более читабельнее и не режет глаза:

$arg = 'T';
if ($arg == 'B') $d = 'bus';
elseif ($arg == 'A') $d = 'airplane';
elseif ($arg == 'T') $d = 'train';
elseif ($arg == 'C') $d = 'car';
elseif ($arg == 'H') $d = 'horse';
else $d = 'feet';
echo $d; // train

Хотя в идеале сюда подошел бы switch:

$arg = 'T';
switch ($arg) {
    case 'B': $d = 'bus'; break;
    case 'A': $d = 'airplane'; break;
    case 'T': $d = 'train'; break;
    case 'C': $d = 'car'; break;
    case 'H': $d = 'horse'; break;
    default: $d = 'feet';
}
echo $d; // train

Если исправить ваш код, путем добавления правильных скобок (работает в php 7.4), то:

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

Как уже сказал @СергейМишин, спасибо ему за комментарий, более логичной и простой для этого подойдет использование ассоциативного массива:

$cfg = [
    'A' => 'airplane',
    'B' => 'bus',
    'T' => 'train',
    'C' => 'car',
    'H' => 'horse',
    'default' => 'feet'
];
$arg = 'T';
echo $cfg[$arg] ?? $cfg['default'];
READ ALSO
конкатенация строки и двух условий if

конкатенация строки и двух условий if

Есть 'строка' в конце которой стоит Тег <br> нужно сделать перенос строки при двух переменных, отображение которых зависит от условия if

232
Проблемы с кодировкой MySQL

Проблемы с кодировкой MySQL

Написал такой код для пангинации, но он почему выводит кракозябры вместо текстаКак это исправить?

104
Как в php выровнять строки по длине

Как в php выровнять строки по длине

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

118
Проблем с платежными системами битрикс

Проблем с платежными системами битрикс

подскажите пожалуйста в чем может быть проблема

66