0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PHPのstrpos()で != false を使うとハマる理由

0
Posted at

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() を使うのも分かりやすいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?