Составление нескольких тернарных операторов в PHP - PullRequest
30 голосов
/ 08 марта 2011

Вот что я написал:

 $Myprovince = (
($province == 6) ? "city-1" :
($province == 7) ? "city-2" :
($province == 8) ? "city-3" :
($province == 30) ? "city-4" : "out of borders"
);

Но для каждого поля я получил значение city-4.Я хочу использовать троичные операторы вместо switch/if, потому что хочу экспериментировать и посмотреть, как это будет сделано.

В чем проблема с этим кодом?

Ответы [ 7 ]

85 голосов
/ 08 марта 2011

Другие уже предложили правильный способ сделать это, но если вы действительно хотите использовать троичный оператор, вам нужно использовать круглые скобки как:

$province = 7;
 $Myprovince = (
 ($province == 6) ? "city-1" :
  (($province == 7) ? "city-2" :
   (($province == 8) ? "city-3" :
    (($province == 30) ? "city-4" : "out of borders")))
 );

Обновленная ссылка

31 голосов
/ 08 марта 2011

Тернарный оператор вычисляется слева направо. Поэтому, если вы не сгруппируете выражения должным образом, вы получите неожиданный результат.

Советы PHP: [документы] :

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

Ваш код фактически оценивается как:

(
    (
        (
            $province == 6 ? "city-1" : $province == 7
        ) ? "city-2" : 
        $province == 8
    ) ? "city-3" : $province == 30
) ? "city-4" : "out of borders";

где это должно быть

$province == 6 ? "city-1" : (
    $province == 7 ? "city-2" : (
        $province == 8 ? "city-3" : (
           $province == 30 ? "city-4" : "out of borders"
        )
    )
);

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


Вам было бы лучше что-то вроде этого:

$map = array( 6 = >'city-1', 
              7 => 'city-2', 
              8 => 'city-3', 
             30 => 'city-4');

$Myprovince = "out of borders";

if(array_key_exists($province, $map)) {
    $Myprovince = $map[$province];
}

Или как @ Иона , упомянутый в его комментарии:

$Myprovince = isset($map[$province]) ? $map[$province] : 'out of borders';
17 голосов
/ 08 марта 2011

Не злоупотребляйте троичным оператором для такого рода вещей. Это делает почти невозможной отладку. Почему бы не сделать что-то вроде

switch($province) {
    case 6: $Myprovince = "city-1"; break;
    case 7: ...
}

или просто цепочка if / then / else

if ($province == 6) {
     $Myprovince = "city-1";
} elseif ($province = ...) {
   ...
}
12 голосов
/ 08 марта 2011

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

$provinces = array (
    6 => 'city-1',
    7 => 'city-2',
    8 => 'city-3',
    30 => 'city-4'
);

// then you can call:

$Myprovince = isset($provinces[$province]) ? $provinces[$province] : 'out of borders';

Почему?

Код, вероятно, со временем станет проще в управлении.Возможно, вы захотите добавить эти сопоставления провинций и городов из базы данных однажды ... и т. Д. Это будет трудно поддерживать с помощью нескольких операторов switch / case.

4 голосов
/ 05 июня 2013

Я понимаю, что это вопрос о PHP, но так как в любом случае это всего лишь учебное упражнение, я подумал, что вам может быть интересно узнать, что Ruby и Javascript действительно ведут себя так, как вы ожидаете.

Ruby:

ree-1.8.7-2012.02 :009 > def foo x
ree-1.8.7-2012.02 :010?>   x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"
ree-1.8.7-2012.02 :011?>   end
 => nil
ree-1.8.7-2012.02 :012 > foo 1
 => "city 1"
ree-1.8.7-2012.02 :013 > foo 2
 => "city 2"
ree-1.8.7-2012.02 :014 > foo 3
 => "out of borders"

Javascript:

> function f(x) { return x == 1 ? "city 1" : x == 2 ? "city 2" : "out of borders"; }
undefined
> f(1)
"city 1"
> f(2)
"city 2"
> f(3)
"out of borders"
3 голосов
/ 08 марта 2011

Попробуйте использовать еще несколько скобок:

$Myprovince = (
($province == 6) ? "city-1" :
(($province == 7) ? "city-2" :
(($province == 8) ? "city-3" :
(($province == 30) ? "city-4" : "out of borders"
))));

В вашем коде есть проблема с приоритетом троичного оператора.

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

0 голосов
/ 08 марта 2011

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

switch ($province) {
    case 6:
        $Myprovince = 'city-1';
        break;
    case 7:
        $Myprovince = 'city-2';
        break;
    case 8:
        $Myprovince = 'city-3';
        break;
    case 30:
        $Myprovince = 'city-4';
        break;
    default:
        $Myprovince = 'out of borders';
}
...