strpos()の挙動に気をつける


TL;DR

  • 第二引数には文字列を渡すこと
  • 扱うPHPのバージョンによって挙動に差異があるので、自身が扱うPHPのバージョンを把握すること

前提

  • PHP ver:7.3.13
  • strposの第一引数をhaystack、第二引数をneedleと以降では記載する
  • 検証環境は、CakePHPのconsoleを利用する

概要

  • strpos()の挙動について注意点を紹介する
    • 主に文字列と数値を渡した場合の挙動について紹介する
    • その他の値を渡した場合の挙動は紹介しない

strpos()については下記の引用を参考に

strpos
(PHP 4, PHP 5, PHP 7)

strpos — 文字列内の部分文字列が最初に現れる場所を見つける

パラメータ ¶
haystack
検索を行う文字列。

needle
needle が文字列でない場合、 数値に変換され、文字の通常の値として扱われます。 この振る舞いは PHP 7.3.0 以降では推奨されないので、 この機能を使用しないことを強く推奨します。 意図した動作に依存する場合、 needle を string に明示的にキャストするか、 明示的に chr() 関数を呼び出すべきでしょう。

offset
指定すると、文字列内での検索開始位置がその位置になります。 負の数を指定すると、文字列の末尾からこの数だけ戻った場所から検索を開始します。

返り値 ¶
needle が見つかった位置を、 haystack 文字列の先頭 (offset の値とは無関係) からの相対位置で返します。 文字列の開始位置は 0 であり、1 ではないことに注意しましょう。

needle が見つからない場合は FALSE を返します。

引用元:https://www.php.net/manual/ja/function.strpos.php

検証

1. haystack ・ needleに "文字列" を渡す

>>> $haystack = '100';
=> "100"
>>> $needle = '100';
=> "100"
>>> strpos($haystack, $needle)
=> 0
  • strpos()の実行結果が0を返してるので、needleが見つかった事が確認できる

2. haystackは "文字列" 、needleは "数値" を渡す

>>> $haystack = '100';
=> "100"
>>> $needle = 100;
=> 100
>>> strpos($haystack, $needle)
PHP Deprecated:  strpos(): Non-string needles will be interpreted as strings in the future. Use an explicit chr() call to preserve the current behavior in /var/www/hoge.jpeval()'d code on line 1
=> false
  • strpos()の実行結果がFALSEを返してるため、needleが見つからなかった事が確認できる
  • また、PHP Deprecatedというエラーが表示されている
    • needleに対して文字列ではない値を渡している事によるエラー
    • PHPドキュメントに記載されてるように、PHP 7.3以降では、needleに渡された値を文字列に変換するという処理は行われない

3. haystackは "数値" 、needleは "文字列" を渡す


>>> $haystack = 100;
=> 100
>>> $needle = '100';
=> "100"
>>> strpos($haystack, $needle)
=> 0
>>>
  • strpos()の実行結果が0を返してるので、needleが見つかった事が確認できる

所感

  • この検証を実施するきっかけとなったのが、検証2が発生したからなんだが、そもそもstrpos()がそこまで型に厳格な関数だと初めて知った(PHPという言語自体そこまで型に厳格な言語ではないという認識もあったので)
  • また、PHPドキュメントを見る限りhaystackには文字列を渡さなければならない感があるんだが、検証3にあるように、文字列以外の値(今回でいうと数値)を許容してるのは何故なのか・・・?
  • 言語という大枠で見るべきか、関数という枠で見るべきなのか、ちょっとわからないが、型に対して厳格さと寛容さの狭間にあるこの状態に気持ち悪さを感じるのは致し方ない事なのか・・・?

以上