PHPの strpos() 判定で != false は使わないほうが良い!!
PHPで文字列の中に特定の文字列が含まれているかを判定するとき、strpos() を使うことがあります。
if (strpos($text, 'abc') != false) {
echo '見つかりました';
}
一見これで良さそうに見えますが、この書き方には注意が必要です。
結論から言うと、strpos() の判定では次のように書くのが安全です。
if (strpos($text, 'abc') !== false) {
echo '見つかりました';
}
strpos() の戻り値
strpos() は、対象の文字列が見つかった場合、その位置を数値で返します。
$text = 'abcdef';
var_dump(strpos($text, 'a')); // int(0)
var_dump(strpos($text, 'b')); // int(1)
var_dump(strpos($text, 'c')); // int(2)
文字列の先頭で見つかった場合、戻り値は 0 になります。
一方、見つからなかった場合は false を返します。
$text = 'abcdef';
var_dump(strpos($text, 'z')); // bool(false)
つまり、strpos() の戻り値は以下のようになります。
見つかった場合 : 位置を表す数値
先頭で見つかった場合: 0
見つからない場合 : false
!= false が危険な理由
PHPでは、0 はゆるい比較では false と同じように扱われます。
そのため、次のようなコードは意図通りに動きません。
$text = 'abcdef';
if (strpos($text, 'a') != false) {
echo '見つかりました';
} else {
echo '見つかりませんでした';
}
a は文字列の先頭に存在します。
しかし、strpos($text, 'a') の戻り値は 0 です。
そして、0 != false は false になります。
その結果、実際には見つかっているのに、見つかりませんでした 側に入ってしまいます。
!== false を使う
この問題を避けるために、strpos() の戻り値を判定するときは厳密比較を使います。
$text = 'abcdef';
if (strpos($text, 'a') !== false) {
echo '見つかりました';
} else {
echo '見つかりませんでした';
}
!== は型も含めて比較します。
そのため、0 と false は別物として扱われます。
var_dump(0 != false); // bool(false)
var_dump(0 !== false); // bool(true)
これにより、文字列の先頭で見つかった場合でも正しく判定できます。
PHP 8以降なら str_contains() も使える
PHP 8以降であれば、単純に「含まれているか」を判定したい場合は str_contains() も使えます。
if (str_contains($text, 'abc')) {
echo '見つかりました';
}
str_contains() は戻り値が true / false なので、strpos() のように 0 を考慮する必要がありません。
ただし、古いPHPバージョンを使っている場合や、位置情報も必要な場合は strpos() を使います。
まとめ
strpos() は、文字列が見つかった位置を返します。
先頭で見つかった場合は 0 を返します。
しかし、PHPのゆるい比較では 0 は false と同じように扱われるため、!= false で判定すると誤判定することがあります。
そのため、strpos() の判定では次のように書くのが安全です。
if (strpos($text, 'abc') !== false) {
// 見つかった場合の処理
}
単純に含まれているかだけを判定したい場合は、PHP 8以降なら str_contains() を使うのも分かりやすいです。