Укладка нескольких тернарных операторов в PHP
Вот что я написал:
$Myprovince = (
($province == 6) ? "city-1" :
($province == 7) ? "city-2" :
($province == 8) ? "city-3" :
($province == 30) ? "city-4" : "out of borders"
);
Но для каждого поля я получил значение city-4
. Я хочу использовать тернарные операторы вместо switch/if
, потому что я хочу поэкспериментировать и посмотреть, как это будет сделано.
В чем проблема с этим кодом?
Ответы
Ответ 1
Другие уже предложили правильный способ сделать это, но если вы действительно хотите использовать троичный оператор, вам нужно использовать круглые скобки как:
$province = 7;
$Myprovince = (
($province == 6) ? "city-1" :
(($province == 7) ? "city-2" :
(($province == 8) ? "city-3" :
(($province == 30) ? "city-4" : "out of borders")))
);
Обновленная ссылка
Ответ 2
Тернарный оператор оценивается слева направо. Поэтому, если вы не сгруппируете выражения должным образом, вы получите неожиданный результат.
Совет PHP - [docs]:
Рекомендуется избегать "укладки" троичных выражений. Поведение 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];
}
Или как @Jonah упомянул в своем комментарии:
$Myprovince = isset($map[$province]) ? $map[$province] : 'out of borders';
Ответ 3
Не злоупотребляйте тернарным оператором для такого рода вещей. Это делает отладки почти невозможным. Почему бы не сделать что-то вроде
switch($province) {
case 6: $Myprovince = "city-1"; break;
case 7: ...
}
или просто несколько цепочек, если /then/else
if ($province == 6) {
$Myprovince = "city-1";
} elseif ($province = ...) {
...
}
Ответ 4
Некоторые люди предложили использовать оператор 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.
Ответ 5
Я понимаю, что это вопрос о 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"
Ответ 6
Попробуйте еще скобки:
$Myprovince = (
($province == 6) ? "city-1" :
(($province == 7) ? "city-2" :
(($province == 8) ? "city-3" :
(($province == 30) ? "city-4" : "out of borders"
))));
В вашем коде есть проблема с приоритетом троичного оператора.
Но я думаю, что вы действительно должны отказаться от этого оператора и вместо этого использовать switch
.
Ответ 7
Вместо этого используйте переключатель. Тернарные операторы действительно не должны использоваться для более чем одного условия, так как они быстро становятся очень трудными для понимания.
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';
}
Ответ 8
Я попал в ту же проблему сегодня. Остальные уже дают приемлемые решения. Мой просто акцент на один лайнер, если. На мой взгляд, более читабельно.
if ($province == 6) $Myprovince = 'city-1';
elseif ($province == 7) $Myprovince = 'city-2';
elseif ($province == 8) $Myprovince = 'city-3';
elseif ($province == 30) $Myprovince = 'city-4';
else $Myprovince = 'out of borders';