え? どこから 1 が出てきたんですか? 意味が分からないのですが……
落ち着いてください、解説しますよ。
この記事の要点
- PHP では
??
の代わりに||
を使うべきではない - 必要であれば
?:
を使っても良い(※後述)
論理演算子と暗黙の型変換
- 論理演算の結果は必ず bool (
true
またはfalse
) - オペランドは bool に暗黙的に変換される
となります。このため、
-
null
および""
はfalse
に暗黙的に変換される -
"a"
はtrue
に暗黙的に変換される
となります。従って、 (null || "") . ("a" || "")
は false . true
となります。
文字列結合演算子と暗黙の型変換
- 文字列結合の際、オペランドは string に暗黙的に型変換される
となります。このため、
-
true
は"1"
に暗黙的に変換される -
false
は""
に暗黙的に変換される
となります。従って、 false . true
は "1"
となります。
isset 判定の有無について
また ??
には isset 判定も含まれていますので、その意味でも ||
や ?:
では代用できません。
?:
(エルビス演算子)
Null 合体演算子 (??
) では、左辺が null の場合のデフォルト値を指定することができました。では、左辺値が falsy な値である場合のデフォルト値を指定したい場合はどうすれば良いのでしょうか。
PHP において、その場合は ?:
(エルビス演算子) というのを使うといいようです。
$a = 10;
print($a ?: "\$a is falsy"); // => 10
$b = "";
print($b ?: "\$b is falsy"); // => $b is falsy
(null ?: "") . ("a" ?: "") // => "a"
(余談)このような誤ったコードを書いてしまった経緯の説明
- JavaScript では
?:
のような意味で||
を使うことがあった- 古い JavaScript では
??
という演算子が存在しなかったため
- 古い JavaScript では
- そのため、PHP でもそのように書いてしまった
PHP に ?? という演算子が存在するかどうかを調べるのが面倒だった ←本音
2. イディオムっぽい使い道「条件分岐の省略」
論理演算子はしばしば 条件分岐の省略 の為に使われます。
- ただし TypeScript で strict-boolean-expressions 等が指定されている場合はそのような使い方はできないし、型を無視した表現のため、現在ではどちらにせよ
??
の代わりに JavaScript の||
を積極的に使うべきではない- しかし、論理演算子の左辺のみがとなる書き方は使用できる
App.tsx
// tsx (TypeScript)
{
// && の右辺は boolean ではない
isMyComponentVisible === true && (
<div>
<MyComponent />
</div>
)
}