strpos()が0を返すと if文でfalseと同じに扱われてしまう
strpos()は文字列が先頭(添字0)で見つかった場合、戻り値の0を返します。if ($pos)のように真偽値として直接判定すると、0はfalseとして扱われるため、先頭で見つかったのに「見つからなかった」と誤判定します。
なぜエラーが出ないのか
出力: not found
(エラーなし)- PHPは何も報告しません。文法として正しいためです
出力: not found- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 <?php 2 $haystack = "hello world"; 3 $pos = strpos($haystack, "hello"); 4 if ($pos == false) { ^ 5 echo "not found"; 6 } else { 7 echo "found"; 8 }
strposは"hello"を添字0で見つけたため0を返します。==で比較すると0とfalseは等しいとみなされ、見つかっているのに「not found」と誤判定します。型まで比較する===が必要です。
直し方: == を === にします。
パターン2
1 <?php 2 $text = "abc123"; 3 $pos = strpos($text, "abc"); 4 if ($pos ) { ^ 5 echo "found at start"; 6 } else { 7 echo "not found"; 8 }
strposは先頭(添字0)で見つかると0を返しますが、if ($pos)は0をfalseとして扱います。$pos !== falseのように型まで比較する必要があります。
直し方: $pos を $pos !== false にします。
パターン3
1 <?php 2 $url = "https://example.com"; 3 $pos = strpos($url, "https"); 4 if ($pos ) { ^ 5 echo "secure"; 6 } else { 7 echo "not secure"; 8 }
"https"は0番目で見つかるため$posは0です。if ($pos)はfalsyな0として扱ってしまうので、!==falseで比較する必要があります。
直し方: $pos を $pos !== false にします。
パターン4
1 <?php 2 $haystack = "abcdef"; 3 $pos = strpos($haystack, "abc"); 4 if ($pos == false) { ^ 5 echo "not found"; 6 } else { 7 echo "found"; 8 }
strposは"abc"を添字0で見つけたため0を返します。==で比較すると0とfalseは等しいとみなされます。
直し方: == を === にします。
パターン5
1 <?php 2 $text = "xyz789"; 3 $pos = strpos($text, "xyz"); 4 if ($pos ) { ^ 5 echo "found at start"; 6 } else { 7 echo "not found"; 8 }
strposは先頭で見つかると0を返しますが、if ($pos)は0をfalseとして扱います。
直し方: $pos を $pos !== false にします。
よくある誤解
「0以上の値が返ってきたなら見つかったはず」という思い込みは、if文でそのまま真偽判定すると崩れます。PHPの0は偽として扱われるため、必ず===falseで比較する必要があります。
実務での勘所
この罠はPHPの有名な落とし穴の1つとして広く知られており、これを根本的に解消するため、PHP 8.0でstr_contains()という新しい関数が追加されました。str_contains($haystack, $needle)は位置ではなく素直なtrue/falseだけを返すため、0との比較を気にする必要が一切ありません。「含まれているかどうか」だけを知りたい場合は、strposを使わずstr_containsを使うのが、PHP 8以降では最も安全な選択です。