読んでほしい人
いきなりですがPHPで**'0です' == 0
** が**true
なのかfalse
**なのか迷った方ははぜひ見て下さい。
はじめに
PHPで等しいかどうか判別をするときは**==
か===
**を使います。
**==
**を使うとPHPは型の判定を行わず、値をなんかいい感じにキャストして比較をしてくれます。
例えば、
**null == 0
や'0' == 0
なんかはtrue
**になります。
このあたりは基本的な話なので、みなさん知ってるわ!って感じですよね。すみません。
しかし、比較演算子**==
**の仕様にはもう少し罠があり、僕はまんまとハマってしまったので本記事でご紹介していきたいと思います。
比較演算子 == の罠
さっそくですが下記プログラムを実行します。
$zero = [0, null, '', '0', 'news zero', 'Re:ゼロ', '0じゃないよ', '1です'];
foreach ($zero as $value) {
if ($value == 0) {
print '0だよ' . PHP_EOL;
} else {
print '0じゃないよ' . PHP_EOL;
}
}
このプログラム、どのような結果になると思いますか?
少し考えてみて下さい。
答え
ーーーーーーーーーー 0だよ 0だよ 0だよ 0だよ 0だよ 0だよ 0だよ 0じゃないよ ーーーーーーーーーー おそろしいことに`'1です'以外の結果はは全て'0だよ'になります` '0'は分かるけど'news zero'や'Re:ゼロ'も0と判定されてしまうのには納得いきません。 しかも'1です'はしっかり'0じゃないよ'になるハチャメチャっぷり。なぜこうなるのか
結論から言うと
-
[文字列] == [整数]
で比較をすると文字列は整数にキャストされる。 - 整数で始まらない文字列は全て0にキャストされる
- 整数で始まる文字列は、その整数にキャストされる
が理由です。
公式ドキュメントには以下のように記載されています
オペランドが両方数値形式の文字列の場合、もしくは一方が数値で、もう一方が数値形式の文字列の場合、 比較は数値として行われます。 これらのルールはswitch文にも適用されます。型の変換は演算子が === や !== の場合は行われません。 なぜなら、これらの演算子は、値と型を両方比較するものだからです。
つまり、先程のプログラムだと
'news zero' → 0
'Re:ゼロ' → 0
'1です' → 1
という感じでにPHPが勝手に変換しちゃってるんですね。
これって有効的に使える場面あるんだろうか...。
ちなみに公式ドキュメントは、このような挙動になることを赤字でしっかり警告していました。
それに気づかず、なんで文字列と0が同じなんだと困惑していた僕...。
みなさん、困ったときはまず公式ドキュメントをしっかり読みましょう。
最後に
今回の比較演算子の例に限らずPHPは型が曖昧でも動いてしまうので、変数や返り値の型をしっかり意識していきたいですね。
ちなみに、本記事で紹介した仕様はPHP8.0から変更されているようです。
下の記事が参考になるかと思うので、興味ある方はぜひ。
【PHP8.0】非厳密な比較演算子==
の挙動が今さら変更になる