in_arrayは第3引数を付けよう、緩い比較の罠とstrict比較

in_arrayとは値が配列に含まれるか調べる関数です。第三引数を省くと緩い比較で誤爆するため、trueを渡して型まで一致させる厳密比較にするのが安全です。

デフォルトの緩い比較が誤爆する

in_array は第三引数を省略すると == の緩い比較で探します。これが曲者で、型をまたいだ比較が思わぬ一致を生むんですよね。特に数値と文字列が混ざると、直感に反する結果になりやすいです。

$list = ['apple', 'banana', 'orange'];

var_dump(in_array(0, $list)); // PHP7では true になった時代も
var_dump(in_array('1abc', [1, 2, 3])); // 環境次第で意図せぬ一致

PHP 8 で文字列と数値の比較ルールが見直されたので昔ほど派手には誤爆しませんが、それでも緩い比較に頼る設計は危ういと思います。0 や 空文字、null が混ざると今でも足をすくわれます。

第3引数にtrueを渡してstrict比較する

第三引数に true を渡すと === の厳密比較になり、値だけでなく型も一致しないと真になりません。ほとんどのケースでこちらが期待する挙動なので、私は in_array を書くとき反射的に true を付けるようにしています。付け忘れがバグの温床になりがちです。

$ids = [1, 2, 3];

var_dump(in_array('2', $ids));        // true(緩い比較で文字列'2'が一致)
var_dump(in_array('2', $ids, true));  // false(型が違うので不一致)

フォームから来る値は文字列、DBのIDは整数、というありがちな組み合わせで、strict を付けていないと「一致するはずなのに、しないはずが一致する」という混乱が起きます。

array_searchやarray_keysも同じ罠を持つ

この緩い比較の問題は in_array だけの話ではなく、array_search や array_keys にも同じ第三引数があります。キーを探す関数も軒並み既定が緩い比較なので、型が絡むなら strict を付けるのが安全ですね。存在チェックだけならキーで持たせて isset を使う手もあります。

$key = array_search('2', [1, 2, 3], true); // 型も一致で探す
// 存在チェックだけなら、値をキーにして isset が速くて堅い
$set = ['a' => true, 'b' => true];
var_dump(isset($set['a'])); // 緩い比較の心配がない

まとめ

in_array の第三引数は、付けないと緩い比較で予想外の一致を招くので、迷ったら true を付ける、くらいの習慣にしておくと安全だと思います。array_search なども同じ事情を抱えているので合わせて意識したいところですね。存在確認が主目的なら、そもそも値をキーにして isset で見る設計にすると、比較の罠自体を回避できる気がします。

よくある質問

Q. 第三引数を付けないとどうなりますか?
A. ==の緩い比較で探すため、型をまたいだ思わぬ一致が起きます。0や空文字、nullが混ざると特に危険です。

Q. 厳密に比較するには?
A. 第三引数にtrueを渡すと===の厳密比較になり、値だけでなく型も一致しないと真になりません。

Q. 同じ罠を持つ関数はありますか?
A. array_searchやarray_keysも同じ第三引数を持ちます。存在確認だけなら値をキーにしてissetで見る手もあります。

類似投稿

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です