TL;DR
<?php
$hogeArray = ["hoge", "foo", "bar"];
// PHP 7まで
in_array(0, $hogeArray); // true(意図しない挙動)
in_array(0, $hogeArray, true); // false
// PHP 8
var_dump(in_array(0, $hogeArray)); // false
PHP 8からは、in_array
の第三引数を省略しても、上記のような意図しない挙動が防げるようになる。
背景
非厳密な比較演算子==
の挙動が変更になる
2020/11/26より、PHPの5年ぶりの時期メジャーバージョンアップであるPHP 8がリリースされます。JITなど、重要なRFCが目白押しですが、その中に「非厳密な比較演算子 ==
の挙動が変更になる」というものがあります。
詳しくは、PHP RFC: Saner string to number comparisons や、他の方が書かれた分かりやすい記事【PHP8.0】非厳密な比較演算子==
の挙動が今さら変更になるをご参照ください。
本記事の主題に入る前に、非厳密な比較演算子==
の挙動の変更について述べる必要があるため、ざっくりと説明します。
数値(例:0
)と数値文字列(例:"0"
)を非厳密演算子 ==
で比較する場合、数値文字列は数値に変換されて文字列比較されます。
<?php
0 == "0"; // true
それ以外の場合(例:数値と数値文字列以外の文字列の比較)は、文字列を数値に変換して比較します。数値文字列以外の文字列を数値へ変換した場合は 0
になるので、以下の結果になります。
<?php
0 == "hoge"; // true
しかし、PHP 8へのメジャーバージョンアップデートによって、 ==
の挙動が変わります。
数値文字列以外の文字列と数値を比較する場合は、数値を文字列に変換してから、文字列比較するようになります。
<?php
0 == "hoge"; // false
in_arrayの挙動が変わる
本記事の主題です。
非厳密な比較演算子 ==
の挙動の変更により、in_array
の挙動も変更となります。
in_array
は、第3引数でstrictが設定されていない限りは型の比較は行いません。つまり、 ==
を使って比較しています。
そのため、今までは意図しない挙動を予防するために、in_array
の第3引数には true
をつける必要がありました。
参考:in_arrayを使うときは黙って第三引数を付けること
ですが、今回のPHP 8へのメジャーバージョンアップデートによって、==
の挙動が変更になったことにより第3引数にtrue
を付けなくとも、意図しない挙動が起きなくなります。
<?php
$hogeArray = ["hoge", "foo", "bar"];
in_array(0, $hogeArray); // false
さいごに
PHP 8の登場により、非厳密な比較演算子 ==
での比較はより安全になりました。
以下に示した例で、$needleSample
が 0
などになっているエッジケースが起こった場合にin_array
の第3引数を付け忘れていたことで、問題の特定に開発者が頭を抱えることが少なくなりそうです。
<?php
$hogeArray = ["hoge", "foo", "bar"];
if (in_array($needleSample, $hogeArray)) {
// なんかの処理
}
注意: この記事は ==
での比較が今までより安全になったから、これからはin_array
の第3引数の省略をとにかく推奨する内容ではありません。
自分の調べた範囲では、第3引数を省略しても、今まで発生していた意図しない挙動を防ぐことを確認できましたが、調査し切れておらず防げないパターンがあるかもしれません**(是非ご指摘ください)**。
よって、第3引数を省略して、業務コーディング中に防げないパターンについてあれこれ考察するのは時間を浪費です。乱暴な言い方ですが、これからも困ったら第3引数のstructをtrue
にしておけば安定です。
補足(2020/11/26まで)
メジャーアップデートは2020/11/26ですが、その前にPHP 8の挙動を確認したい方は、
PHP 8.0のイメージをpullしてこればカレントディレクトリにPHPファイルを置いて、以下のようにPHP 8環境で挙動を試すことができます。
docker run --rm -v `pwd`:/app -w /app php:8.0-rc php php8test.php