PHPの三項演算子はネスト、つまり三項演算子の項に三項演算子を使った式を使うことができるが、PHPの三項演算子は右から順に評価されるので注意が必要だ。
いろんな言語で次のようにネストした三項演算式が書ける。
true ? 1 : true ? 2 : true ? 3 : 4
多くの言語1は、次のように右から評価していく。
true ? 1 : (true ? 2 : (true ? 3 : 4))
true ? 1 : (true ? 2 : 3 ))
true ? 1 : 2
1
しかしPHPは、左から評価していく。
((true ? 1 : true) ? 2 : true) ? 3 : 4
( 1 ? 2 : true) ? 3 : 4
2 ? 3 : 4
3
したがって、例えば、1なら「one」、2なら「two」、3なら「three」、それ以外なら「more」をマッピングしたい気持ちで次のような三項演算子の式を書くと思いがけない罠にはまる。
$value = 2;
var_dump(
$value === 1 ? 'one' :
$value === 2 ? 'two' :
$value === 3 ? 'three' : 'more'
); //=> string(5) "three"
上のコードは次のように計算された結果、"three"が答えになる。
(($v === 1 ? 'one' : $v === 2) ? 'two' : $v === 3) ? 'three' : 'more'
^^
((2 === 1 ? 'one' : $v === 2) ? 'two' : $v === 3) ? 'three' : 'more'
^------^
((false ? 'one' : $v === 2) ? 'two' : $v === 3) ? 'three' : 'more'
^^
((false ? 'one' : 2 === 2) ? 'two' : $v === 3) ? 'three' : 'more'
^------^
((false ? 'one' : true ) ? 'two' : $v === 3) ? 'three' : 'more'
^---------------------------^
(true ? 'two' : $v === 3) ? 'three' : 'more'
^------------------------------------------------^
'two' ? 'three' : 'more'
^-------------------------------------------------------------------^
'three'
上記のようなマッピングをしたい場合は、ifやswitch、連想配列など他の手立てを使ったほうがいい。
$value = 2;
var_dump(
(function (int $value): string {
if ($value === 1) return 'one';
if ($value === 2) return 'two';
if ($value === 3) return 'three';
return 'more';
})($value)
); //=> string(3) "two"
var_dump(
(function (int $value): string {
switch ($value) {
case 1: return 'one';
case 2: return 'two';
case 3: return 'three';
default: return 'more';
}
})($value)
); //=> string(3) "two"
var_dump(
(function (int $value): string {
return [
1 => 'one',
2 => 'two',
3 => 'three'
][$value] ?? 'more';
})($value)
); //=> string(3) "two"
-
Java, Swift, Ruby, JavaScriptなど ↩