はじめに
- phpでin_array使ってますか?
- その時、第3引数って使ってますか?
- 使ってない?いつ事故ってもおかしくないですよ?
まずは普通に使ってみる
<?php
$students = ['山本', '山下', '山田'];
var_dump(in_array('山田', $students)); // trueを返すはず
var_dump(in_array('山原', $students)); // falseを返すはず
実行してみましょう。山原さんは$students
にいないのでfalse返すはずですよね。
$ php test.php
bool(true)
bool(false)
はい。想定通りですね。
じゃあ問題です
<?php
$numbers = [0, 1, 2, 3, 4, 5];
var_dump(in_array(3, $numbers)); // trueを返すはず
var_dump(in_array('山原', $numbers)); // falseを返すはず
さぁ、どうなるでしょうか?
$ php test.php
bool(true)
bool(true)
なんという事でしょう!!
山原
なんて文字列は$numbers
に含まれてないのにtrueを返してきました。
一体何が起きたのか
マニュアルを読んで見ましょう。
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
needle で haystack を検索します。 strict が設定されていない限りは型の比較は行いません。
なんという事でしょう。
第三引数のstrict
はデフォルトでfalseになっているため、型比較までしない。
つまり、==
で比較してるわけですね。
これがPHPの悲しい所ですが、1つ簡単な実験をします。
<?php
var_dump('山原' == 0);
var_dump('山原' === 0);
さぁ、これはどうなるでしょうか。両方falseになると思いがちですよね。
$ php test.php
bool(true)
bool(false)
なんと・・・
これがPHPな訳です。
答えは、比較演算子に書いてあります。
例 名前 結果
$a == $b 等しい 型の相互変換をした後で $a が $b に等しい時に TRUE。
型の相互変換をした後で
とありますね。
つまり、これが暗黙の型変換ってやつで、文字列と数値を比較する場合には暗黙の間に文字列の型変換が行われて0
になってしまうのです。
怖いかもしれませんが仕様です。
じゃあどうすればよいのか?
答えですが、in_array使うときは黙って第三引数にtrueを指定しなさいです。
元のコードに戻って、in_arrayの第三引数にtrueを指定して型までチェックさせてみます。
<?php
$numbers = [0, 1, 2, 3, 4, 5];
var_dump(in_array(3, $numbers, true)); // trueを返すはず
var_dump(in_array('山原', $numbers, true)); // falseを返すはず
いざ・・!
$ php test.php
bool(true)
bool(false)
ようやく想定どおりの結果になりました。
PHPでは色んな罠がありますが、これも一種です。
サーバアプリケーションでは、受け取った値を元にバリデーションするシーンで使う機会は多いと思います。
そんな時に通っちゃいけない文字列が通るという危険なバグになりかねないです。
最後にもう一度
in_array使うときは黙って第三引数にtrueを指定しなさい
以上です。