PHP

忘れやすい人のための三項演算子の省略形【PHP】

More than 1 year has passed since last update.


まえがき

PHPの三項演算子は場合によって省略形で書けることがありますが、省略形が2つあってどっちがどっちだか分からなくなる(自分だけ?)のでメモとして残しておきます。

そもそも論として「三項演算子は可読性が下がるからやめよう」的な話は昔からあるのですが、そういった宗教戦争はここではおいておきます。Qiita内にもたくさん記事があるのでそちらを参照してください。個人的には「好きにすりゃええんじゃ...! (cv. 千鳥ノブ)」という感じです。


エルビス演算子 ?:

これはPHP 5.3以降で登場した記法で、

$a ? $a : $b;

という場合には、

$a ?: $b;

と書けるというものです。一見分かりづらいように思えますが、

const DEFAULT_NAME = '以下、名無しにかわりましてVIPがお送りします';

public function postComment(string $comment, string $name = '')
{
$displayName = $name ?: self::DEFULT_NAME;

// (ellipsis)
}

public function getFavoriteList(): FavoriteList

{
$favoriteList = $this->favoriteRepository->get($this->userId); // FavoriteList or null

return $favoriteList ?: new FavoriteList([]);
}

などの例のように、 デフォルト値 として使うと可読性を下げずに短く書けるかと思います(下の例はそもそもRepositoryがList返しておけよという感じですがまぁ...)。今さらですが日本語公式リファレンスを引用。


PHP 5.3 以降では、三項演算子のまんなかの部分をなくすこともできるようになりました。 式 expr1 ?: expr3 の結果は、expr1 が TRUE と同等の場合は expr1、 それ以外の場合は expr3 となります。


つまり、 false, null, 0, ''(空文字), [](空配列) などのときのデフォルト値として使えます。便利ですね。


null合体演算子 ??

こちらはPHP 7から登場した記法で、エルビス演算子同様にデフォルト値として使うことができるのですが、大きな違いは存在しない値にアクセスしてもPHP Noticeを出さないという点です。


式 (expr1) ?? (expr2) は、 expr1 が NULL である場合は expr2 と評価され、それ以外の場合は expr1 と評価されます。

この演算子は、左側の値が存在しない場合でも notice が発生しません。 isset() と同じ挙動です。


これは配列を扱う時に非常に便利です。

public function __construct(array $config = [])

{
$this->handler = $config['handler'] ?? new DefaultHandler();
$this->callback = $config['callback'] ?? null;
$this->trial = $config['trial'] ?? 10;
}

ただし注意が必要なのは isset()と同じ挙動 なので、falseや0、空文字などは真と判断され左側の値が使われます。このへんの型比較は意外と忘れがち(自分だけ?)なので一応リンクを貼っておきます。

$value = '';

echo $value ?: 'Hello World!'; // Hello World!

echo $value ?? 'Hello World!'; // (No Output)

また、当然ながら評価する前にアクセスしようとするとNoticeが発生します。

unset($url);

$path = str_replace('https://mangamura.org/', '', $url) ?? 'home'; // Notice

$queryParameters = [

'searchWord' => 'コナン',
'replyWord' => '真犯人は...',
];

$currentPage = (int)$queryParameters['page'] ?? 1; // Notice

こういうケースでは素直に省略せずに書くか、そもそもこの処理にくる以前のロジックフローを見直す方が良いでしょう。それと仮にできたとしてもこのような書き方は可読性が下がるので、アンチ三項演算子派の方々に怒られそうですね。


まとめと使い分け


  • false と等価な値をデフォルト値で置き換えたい -> エルビス演算子 ?:


  • 未定義や配列の存在しないIndexの可能性がある値にデフォルト値をセットしたい -> null合体演算子 ??


  • 存在していないまたはfalseと同等なら置き換えたい -> !empty($undefined) ? $undefined : $default; とでもするしかない


という感じでしょうか。一応例に出したものは動作確認を行った(PHP 7.2.5)はずですが、間違い等ありましたら指摘していただけると助かります。