странное поведение тернарный оператор

Исходя из C #, я должен сделать проект в 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

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

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

 $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' 

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

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

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

  $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' true ? 'train' : 'false' to 'train' :

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

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

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

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

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

Это не работает должным образом из-за ошибки в грамматике языка 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 или ассоциативный массив и быть более читабельным.

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

Я точно не знаю, почему вы решили использовать эту форму синтаксиса, как упоминалось в комментарии , это было бы кошмаром для отладки … Возможно, здесь лучше выбрать коммутатор –

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

Рекомендации –

  • switch statement

Научитесь любить 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 при использовании нескольких тернарных операторов в одном выражении неочевидно: