三項演算子は、1つの式に収まるif/elseです:condition ? valueIfTrue : valueIfFalse。2つの値のどちらかを返すので、代入したり、echoしたり、関数に渡したりできます。
$ageを15に、$itemsを3に変えて、もう一度実行してみてください。最後の行で三項演算子を括弧で囲んでいる点に注目してください。括弧がないと.が先に文字列を結合してしまい、意図した結果になりません。
HTMLテンプレートの中の三項演算子
テンプレートの中でCSSクラス、ラベル、属性を選ぶときは、三項演算子を使うのが定番です。このブロックはURLから?stock=を読み取ります。実行してからPageタブのリンクをクリックすると、別の値で同じスクリプトがもう一度実行されます。
<?= ... ?>は<?php echo ... ?>の短縮形で、マークアップの中でも1行の条件を読みやすく保てます。
省略形の三項演算子?:(エルビス演算子)
真ん中の部分を省くと$a ?: $bになります。$aがtrueと評価される値なら$aを、そうでなければ$bを返します。空文字列や0のときも代わりの値にしたい場合の既定値に便利です。
falseと評価される値はfalse、0、0.0、""、"0"、[]、nullです。データの中で"0"が正当な答え(数量の欄、暗証番号)である場合、省略形の三項演算子はそれを捨ててしまいます。
?:と??の違い
見た目は似ていますが、確認する内容が違います。?:は左辺がfalseと評価される値のときに代わりの値を使います。??は左辺がnullか未設定のときだけ代わりの値を使い、存在しない変数や配列キーについて警告を出しません。
「値が存在しないかもしれない」(リクエストのデータ、設定の配列、任意のキー)には??を使い、「値は存在するが空かもしれない」には?:を使います。??と??=についてはnull合体演算子のページで詳しく扱っています。
ネストした三項演算子には括弧が必要
PHP 7は、ほかのほとんどの言語と違ってa ? b : c ? d : eを左から右に読み、間違った結果を出していました。PHP 8は推測を拒否します。
<?php
echo $score > 90 ? "A" : $score > 80 ? "B" : "C";
PHP Fatal error: Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` in /home/index.php on line 2
内側の三項演算子を括弧で囲めば動きます。
省略形の三項演算子は例外で、上のエルビスの例のように$a ?: $b ?: $cは括弧なしで書けます。
分岐が3つ以上ならmatch(true)を使う
3段や4段にネストした三項演算子は、括弧があっても読みにくくなります。trueを対象にしたmatchは、条件を上から順に調べて、最初に一致したアームを返します。
1行で2つの結果を選ぶときは三項演算子を使い、3つ目が必要になったらすぐにmatchかif/elseifの連鎖に切り替えましょう。
よくある質問
PHPの三項演算子とは何ですか?
値を返すif/elseの短縮形です:$label = $age >= 18 ? 'adult' : 'minor';。?の前の条件がtrueなら?のあとの式が、そうでなければ:のあとの式が使われます。
PHPの?:はどういう意味ですか?
$a ?: $bは省略形の三項演算子(エルビス演算子とも呼ばれます)です。$aがtrueと評価される値なら$aを、そうでなければ$bを返すので、'' ?: 'default'は'default'です。$a ? $a : $bと同じですが、$aは1回しか評価されません。
PHPで三項演算子をネストできますか?
括弧を付ければできます。PHP 8以降、$a ? 'x' : $b ? 'y' : 'z'は致命的エラーなので、$a ? 'x' : ($b ? 'y' : 'z')と書きます。分岐が3つ以上なら、match(true)かif/elseifの連鎖のほうが読みやすくなります。
else部分のない三項演算子は使えますか?
使えません。三項演算子には常に両方の分岐が必要です。「この値、なければ代わりの値」なら$x ?: 'default'か$x ?? 'default'と書き、条件が成り立つときだけ何かをするなら、普通のifか$condition && doSomething();と書きます。