strpos($haystack, $needle)は、$haystackの中で最初に現れる$needleの位置を0から数えて返し、なければfalseを返します。先頭での一致は0を返すので、結果は必ず!== falseで判定します。
PHP 8で、あるかないかだけがわかればよいなら、str_contains()のほうがわかりやすく書けます。位置が重要なときにstrpos()を使います。
構文
strpos(string $haystack, string $needle, int $offset = 0): int|false
検索は大文字小文字を区別します。$offsetは検索を始める場所を指定し、負のオフセットは文字列の末尾から数えます。
!== falseの落とし穴
0とfalseは、ゆるい比較(==)では等しくなります。そのため、厳密でない判定では、位置0の一致が「見つからない」として扱われます。
同じルールは、本当の一致に対して0を返しうるstripos()、strrpos()、array_search()にも当てはまります。
striposで大文字小文字を区別せずに検索する
stripos()は同じ引数を受け取り、ASCIIの文字の大文字小文字を無視します。
strrposで最後の出現を見つける
strrpos()は最後の一致の位置を返します。ファイルの拡張子やパスの最後の部分を取得する標準的な方法です。
ファイル名に限れば、pathinfo($file, PATHINFO_EXTENSION)がこれをやってくれます。位置で文字列を切る方法はsubstr()のページで扱っています。
オフセットから検索を始める
3つ目の引数は文字列の先頭を飛ばします。負のオフセットは、末尾からその文字数だけ手前から始めます。
すべての出現を見つける
strpos()が見つけるのは1つの一致です。ループして各一致の後ろにオフセットを動かせば、すべてを見つけられます。
数だけが必要なら、substr_count($text, 'the')のほうが短く書けます。パターンなら、PREG_OFFSET_CAPTUREを指定したpreg_match_all()がすべての一致を位置付きで返します。
日本語のテキスト:バイト位置と文字位置
strpos()はマルチバイトのテキストも正しく見つけますが、返す数値はバイト単位です。UTF-8ではかなとよく使う漢字は1文字3バイトなので、日本語だけのテキストではバイト位置は文字位置の3倍になり、混在したテキストではもっとわかりにくい形でずれていきます。mb_strpos()は文字単位で返し、これがmb_substr()の期待するものです。
2つを混ぜるのは定番のバグで、strpos()の結果をmb_substr()に渡すと文字列の奥から始まりすぎてしまいます。strposはsubstrと、mb_strposはmb_substrと組み合わせて使いましょう。
よくある質問
PHPのstrpos()は何を返しますか?
最初の一致の位置を0から数えた整数で返し、見つからなければfalseを返します。strpos('hello', 'l')は2を返します。
strpos()に!== falseが必要なのはなぜですか?
先頭での一致は0を返し、0 == falseはtrueだからです。if (strpos($s, 'a'))は位置0の一致を「見つからない」として扱います。必ずstrpos($s, 'a') !== falseで比較してください。
strpos、stripos、strrposの違いは何ですか?
strpos()は最初の一致を見つけ、大文字小文字を区別します。stripos()は大文字小文字を無視して最初の一致を見つけます。strrpos()は最後の一致を見つけます。strripos()は大文字小文字を無視して最後の一致を見つけます。
文字列にテキストが含まれているか確認するには、strposとstr_containsのどちらを使うべきですか?
PHP 8ならstr_contains($haystack, $needle)を使います。素のtrueかfalseを返し、位置0の罠がありません。位置そのものが必要なときはstrpos()を使います。
日本語のテキストでstrposを使うには?
strpos()は日本語のテキストも正しく見つけますが、返す位置はバイト単位です。その位置をmb_substr()に渡したりユーザーに見せたりするなら、文字単位で位置を返すmb_strpos()を使います。