たかぽんです!
PHPを触っているとよく見かける”??”
それが一体なんなのか・・・?
調べていこうと思います!
??マークとは・・・?
さて、それでは早速ですが結論から。
公式のマニュアルによると、??マークは"null 合体演算子"と呼ばれているようです。
検索で "??" でしらべてもなかなかヒットしないから、"はてなまーくふたつ"や"クエスチョンマークふたつ"でいらっしゃる方も多いかも・・・?w
PHP 7 以降ではさらに、"??" 演算子 (null 合体演算子) が使えるようになりました。
PHP 比較演算子-Manual
じゃぁ、null合体演算子とは・・・?となるわけですが...
簡単に説明すると、Nullかどうか確認することができます。
言葉だけだとわかりづらいので例を出して説明します。
null合体演算子の使い方
公式マニュアルの例は以下の通り。
こちらの例にはnull合体演算子を用いた例とif文で同じ挙動を再現している例の二つが含まれています。
一部わかりやすいように出力用のecho関数の追加、変数名を書き換えていますが、それ以外はマニュアルどうりです。
実行ボタンを押すと??
もif
もどちらもdefault
が$action
に入れられていることを確認できますね。
つまり、NULL合体演算子は演算子の直前に渡された値に対してNULLチェック(isset)を行い、その後NULLだった場合は直後の値を、NULLでなければ渡された値をそのまま返します。
今回はNULLだったので、どちらもdefaultが渡されているわけですね!
式 (expr1) ?? (expr2) は、 expr1 が
PHP 比較演算子-ManualNULL
である場合は expr2 と評価され、それ以外の場合は expr1 と評価されます。
では次は値が入っている場合をみてみましょう!
ここでは$initValue
に対して'hoge'
という文字列をあげています。
これで$initValue
はNULL
ではなくなるので、ちゃんと値が$action
へ代入されるわけですね。
実行結果もhoge
になっています。
NULL
が帰ってくるかもしれないけど、その場合は何か値を入れておきたいなぁ!ってときに使えますね。
null合体演算子のネスト
では次に応用的な部分をみていきます。
null合体演算子はネストができるようです。
ネストというのは"巣"と言う意味ですが、プログラムにおいては再帰的に呼び出すことですね。
ここではnull合体演算子の値としてさらにnull合体演算子を用いた式を入れると行った感じです。
では実際にコードをみていきましょう。
こちらも公式より、一部わかりやすいようにecho
を付け加えています。
最初のechoはマニュアルどうりなんですが、計算順序がわかりづらいので、直後に括弧を付与したものを用意しておきました。
内側の括弧から実行されていきます。
最初は$foo ?? $bar
が評価され、$foo
はnull
なので$bar
が帰ります。
そして次は($foo ?? $bar) ?? $baz
なので、先ほどの結果から、$bar ?? $baz
が評価されます。
$bar
もnull
なので、ここの結果は$baz
に。
そして最後に$baz ?? $qux
が実行されます。
$baz
は1
でnull
でないので、$baz
が返りますね。
結果として出力が1
になるわけです。
ここ、なぜピックアップされているのかというと、計算順序が特殊で、勘違いをする可能性があるからです。
例えばですが...
add(sum(1,2,3,4),mult(5,6));
上記の場合、addよりも先にsumとmultを計算するはずです。
つまり、末端にて計算した結果を使ってより上位の計算を行います。
null合体演算子で上記の計算方法を適応しようとしたらこんな感じになるはずです。
($foo ?? ($bar ?? ($baz ?? $qux)));
まず最初に($baz ?? $qux)を計算し、その結果を使ってさらに上位にある($bar ?? ($baz ?? $qux))をそしてさらに上位を...
という感じです。
ところが実際の動きは異なります。
この順序の捉え方が2通りあり、どちらを適応してもそれっぽい感じになってしまうんですね。
だから、明確に正しい使い方はこうだよ!と順序について触れられています。
ネストする場合は気をつけて使うようにしてください。
(後述しますが、こういった曖昧さが残るため、null合体演算子のネストはあまり推奨されません...)
まとめ
今回はよく見る"??"マークについて調べました。
null合体演算子を使うことで、コードもすごく短くすらっとなるので積極的に使っていけるといいですね。
ただ、あまりネストの用法で用いられているのは未だみたことがないです...。
というのも、ネストをしすぎると順序がわかりづらかったり、そもそも見辛くなる(=可読性の低下に繋がる)場合が多いので、出来るだけ単体(c = a ?? b
の形)で使用したほうが無難だと思います。
null合体演算子は用法用量を守って使用してくださいねっ!
それでわ!