Help us understand the problem. What is going on with this article?

三項演算子をもっと使おう

More than 1 year has passed since last update.

みなさん三項演算子使ってますか?
使いこなせばこれほど便利な演算子はそうそうないですよ。

基本

if($bool){ func1(); }else{ func2(); }
$bool ? func1() : func2();

if($bool){ $a=1; }else{ $a=2; }
$a = $bool ? 1 : 2;

if / elseを三項演算子で置き換える基本例です。
なお三項演算子はif同様==で比較するので、厳密に比較したい場合は===を追加する必要があります。

if($cond===true){ func1(); }else{ func2(); }
$cond===true ? func1() : func2();

応用

ifは文ですが、三項演算子は式です。
式なのでこんなこともできます。

('func'.($bool?'1':'2'))();

$bool==trueであれば関数func1()を、falseならfunc2()を呼び出します。

$arr[$bool?'key1':'key2']=1;

$bool==trueであれば$arr['key1']が1になり、falseなら$arr['key2']が1になります。

${'var'.($bool?'1':'2')}=1;

$bool==trueであれば$var1に、falseなら$var2に1を代入。
?:より.のほうが優先順位が高いので()が必要です。
()を使いたくない場合は、ダミーの変数を挟んで${'var'.$x=$bool?'1':'2'}=1;とします。

優先順位

$bool ? 5+1 : $a.$b;

$bool ? (5+1) : ($a.$b);と解釈されます。
?:の優先順位は、代入演算子よりは高く他の演算子よりは低いため、三項演算子の中にそのまま演算子を書いても怒られません。

$bool ? $a=3 : $a=4;

のはずなのですが、代入演算子はわりと法則を無視して優先されます。
上記は($bool?$a=3:$a)=4;ではなく$bool?($a=3):($a=4);となります。
なお例の場合は$a=$bool?3:4;と書けばいいですが、この書き方を使うと、$bool ? $a=3 : $b=4;と別の変数に突っ込んだりすることができます。

$c = $bool ? 8+$a=2 : 'y'.!$b='x' ;

演算とは全く別の値を返す場合の書き方です。
$bool==trueなら$a=2$c=10に、falseなら$b='x'$c='y'になります。
三項演算子はあくまで式なので、{}や;などで複数の文を記述することができません。
そのため複数の代入をしたい場合はややアクロバティックな書き方になります。

二重三項演算子

それでは基本ができたところで三項演算子を重ねてみましょう。

$a ? $b : $c ? $d : $e;

ぱっと見$a==trueであれば$bに進む、$a==falseであれば$cの結果によって$d$eに進む、と読めます。
実際そのようにする処理系が多いのですが、PHPでは何故か処理順が違います。

// 他の多くの言語
$a ? $b : ($c ? $d : $e);
// PHP
($a ? $b : $c) ? $d : $e;

具体的には$a ? $b : $cの結果が==trueであれば$d、falseであれば$eとなり、出力は2値になります。
どうしてですかね。
多言語と同じように3値を返したい場合は、括弧を入れるか入れ子の順番を変えましょう。

!$a ? $c ? $d : $e : $b;

これで誤解読の余地もなくなります。
欠点としては1文字増えるところでしょうか。

実践

上記程度の知識があれば、わりと自在に三項演算子を書けるようになるかと思います。
手始めに手元のプログラムからifをなくしてみよう。

if($a && $b){ funcAB(); }elseif($a){ funcA(); }elseif($b){ funcB(); }else{ funcN(); }
$a||$b?$a?$b?funcAB():funcA():funcB():funcN();
$a?$b?funcAB():funcA():($b?funcB():funcN());
(func.($a||$b?$a?$b?AB:A:B:N))();
(func.($a?$b?AB:A:($b?B:N)))();

全部同じ結果になります。
ifなんていらんかったんや。

類似品

$a && $b=1;

$a==trueの場合のみ$b=1になります。
三項演算子の左側だけが必要な場合に使います。
え?論理積?何それ?

$a || $b=1;

$a==falseの場合のみ$b=1になります。
こちらは三項演算子の右側だけが必要な場合です。
レガシーコードでたまに見かけるor dieもこれと同じ意味です。

$c = $a ?: $b;

三項演算子の中央を省略した場合、左辺の値になります。
$var = $_REQUEST['var'] ?: 'default';みたいに簡単にデフォルト値を設定できますが、未定義の場合Undefined indexのNoticeが発生してしまいます。

$c = $a ?? $b;

PHP7で追加された書式で、簡単に言うとNoticeの発生しない?:です。
$var = $_REQUEST['var'] ?? 'default';でNoticeが出ません。

$x = $a ?? $b ?? $c ?? $d ?? $e;

??は何個も繋げることができます。?:もですが。
左から順に調べていき、$xは最初にisset()で見つかった値になります。
単純にこう書くと$eでNoticeが出るので、最後にnullとか''とかを置いておくとよいでしょう。

$x = $a<=>$b;

PHP7で追加された宇宙船演算子です。
$a>$bなら1、$a==$bなら0、$a<$bなら-1になります。
ただ、そもそもPHPでは三分岐ができないので、三項演算子と一緒に使う意味はあまりありません。
というか何処で出番があるのかよくわからん。
$a<=>$b?$x:$y;とした場合、$a==$bなら$y、それ以外は$xとなるので、普通に$a!=$b?$x:$yのほうが短いです。

結論

ややこしい三項演算子はやめよう(ここまでやってそれかよ)。
こんなん見せられて読む気になるかって話ですよ。

# 面白い使い方募集中

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした