Странный оператор троичного поведения

Исходя из С#, я должен сделать проект в PHP.

Я использую этот код:

$transport = 'T';

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

echo $vehicle;

Я ожидаю, что он напечатает train, но я получаю horse. Пример Codepad: http://codepad.org/rWllfrht

Кто может объяснить это странное поведение?

Ответ 1

Я не советую вам использовать такой код, но в образовательных целях он должен быть

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

echo $vehicle;

Лучший код должен быть

$transport = 'T';
switch ($transport) {
    case 'A' :
        $vehicle = 'airplane';
        break;
    case 'B' :
        $vehicle = 'bus';
        break;
    case 'C' :
        $vehicle = 'car';
        break;
    case 'H' :
        $vehicle = 'horse';
        break;
    case 'T' :
        $vehicle = 'train';
        break;
    default :
        $vehicle = 'teleportation';
        break;
}

echo $vehicle;

Или еще лучше:

$transport = 'T';
$array = array('A'=>'airplane','B'=>"bus","C"=>"car","H"=>"horse","T"=>"train");
echo isset($array[$transport]) ? $array[$transport] : null;

Или используйте базу данных:

 SELECT name FROM transpotationTable WHERE someKey = '$transport' 

Ответ 2

Не видя каких-либо объяснений о том, почему ваш код нарушен в других ответах, так что это быстрый прогон.

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

Здесь урезана версия вашего кода, которая по-прежнему вызывает неверный результат "лошади":

 $t = 'T';

 ( $t == 'T' ) ? 'train' : 
 ( $t == 'C' ) ? 'car' : 
 ( $t == 'H' ) ? 'horse' : 'feet';

Сначала давайте разворачиваем его:

( $t == 'T' ) ? 'train' : ( $t == 'C' ) ? 'car' : ( $t == 'H' ) ? 'horse' : 'feet'; 

Далее я добавлю явные скобки, где уже есть неявные:

((($t == 'T') ? 'train' : ($t == 'C')) ? 'car' : ($t == 'H')) ? 'horse' : 'feet';

Затем мы можем решить ваши сравнения:

((true ? 'train' : false) ? 'car' : false) ? 'horse' : 'feet';

Вы должны начать понимать, почему это нарушено. Первый тернар оценивает от true ? 'train' : 'false' до 'train':

('train' ? 'car' : false) ? 'horse' : 'feet';

Потому что 'train' имеет значение true при приведении в логическое значение, теперь результат 'car':

'car' ? 'horse' : 'feet';

Опять же, поскольку непустая строка является "истиной", результатом становится теперь "лошадь". Итак, в первый раз, когда в вашем ужасном вложенном примере case появляется true, результат будет каскадом через все остальные операторы, выкинув предыдущее значение для "истинной" ветки следующего оператора.

Решение состоит в том, чтобы избежать этого кода. Это попытка быть далеко, слишком умна, и результат - сломанный, нечитаемый беспорядок. Нет никаких оснований для его использования. Выберите оператор switch, который создан специально для того, что вы пытаетесь сделать.

Ответ 3

Это не работает должным образом из-за ошибки в грамматике языка PHP, как показано на рисунке: http://en.wikipedia.org/wiki/%3F:#PHP

Здесь работает простая версия, которая работает:

$transport = 'T';

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

echo $vehicle;

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

Ответ 4

Это своего рода "поведение" как-будто-даже-хотя-это-явно-неправильное "PHP. Это не связано таким образом, поэтому, пока этот код работает на большинстве других языков, он не сработает на PHP. Урок? Научитесь использовать круглые скобки над необычными парадигмами ассоциации. Урок два? Тернар не волшебная пуля, хотя она может быть красивой и компактной, ее следует использовать только тогда, когда она читается. Вложенные тернарные заявления IMHO просто уродливы.

Ответ 5

Я не уверен точно, почему вы решили использовать эту форму синтаксиса, как указано в comment, это было бы кошмаром для отладки. Здесь может быть лучший вариант переключения -

$vehicle = '';
switch($transport){
  case 'B' :
    $vehicle = 'bus';
  break;
  case 'A' :
    $vehicle = 'airplane';
  break;
  ...
  default:
   // undefined cases
  break;
}

Ссылки -

Ответ 6

Научитесь любить paranthesis, если хотите сделать что-то вроде этого:

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

Каждая правая часть тернарной части должна быть четко записана из-за порядка операций PHP для тройного http://php.net/manual/en/language.operators.comparison.php.

Кстати, с этой страницы они явно рекомендуют не складывать их так...

Примечание. Рекомендуется избегать тройных выражений. Поведение PHP при использовании нескольких тернарных операторов в одном выражении неочевидно: