strpos
や strstr
を使わずに済むようになる・・・かもしれません( 日本語対応にやや懸念あり)。
以下、 RFCをもとに紹介します。
まだ投票中ですが、3月8日現在、賛成42/反対5という圧倒的多数の支持を得ているため、追加される公算が高いです。
既存関数の問題点
ある文字列が別の文字列に含まれているかをチェックする際、これまで strposや strstrといった関数が使われてきました。
しかし、これらの関数は、以下の問題を抱えています。
- 読み手にとってあまり直感的でない
- 間違いやすい
- 新しく PHP に触れる開発者にとって覚えにくい
そのため、多くの PHP フレームワークが、同様の振る舞いをするヘルパー関数を提供しています。それだけ、この機能は、重要だし、必要とされているということです。
提案
概要
str_contains ( string $haystack , string $needle ) : bool
$needle
が $haystack
に含まれているかをチェックし、$needle
が見つかったかを真偽値( true/false
)で返します。
例えば、以下のようになります。
str_contains("abc","a");// truestr_contains("abc","d");// false// $needle が空文字だった場合str_contains("abc","");// truestr_contains("","");// true
$needle
が空文字だった場合については「空文字は文字列のどの位置にも出現する」と考えて true
を返すことにします。
マルチバイト版
内部メーリングリストでの議論を踏まえて、この関数にはマルチバイト版(例えば mb_str_contains
)を提供する必要はないとの結論に至りました。
というのも、マルチバイト版と非マルチバイト版の動作に差がないと考えられるからです。文字列が見つかったオフセットや位置が関係する場合、マルチバイト版は異なる振る舞いをします。
しかし、この関数には、その必要はありません。
大文字小文字を区別しない版
大文字小文字を区別しない版については、今回は実装しません。
提案者は、最初は小さくはじめて、徐々に大きくしていくほうが良いと考えているからです。1
後方非互換性
PHP 自体には後方非互換性はありません。
ただし、ユーザのコードで、この関数を実装している場合、後方非互換が発生するかもしれません。
感想
strpos
は文字列の位置を返す変数ですが、1文字目に含まれている場合は 0
を返します。そして、どこにも含まれていない場合には false
を返します。
PHP では 0 == false
です。そのため、以下のような書き方をすると、バグになってしまいます。
// 1文字目に含まれている場合は 0 が返る$pos=strpos("abc","a");// 間違った書き方if(!$pos){die("含まれていない");}// 正しい書き方if($pos===false){die("含まれていない");}
そもそも strpos
は「文字列の位置を返すための関数」ですし、 strstr
は「部分文字列を抽出するための関数」です。
どちらも文字列が含まれているかをチェックするための関数ではない
strstr
ってなんだよ。str s ubs tr ing のつもりか? 覚えられん!
この使いづらさから、例えば Laravel には Str::contains
という メソッドが用意されていたりしますが、とうとう、PHP 本体にも入ることになったようです。万歳!
気になるのは、「日本語文字コードでも正しく動くか?」ということです。strpos
には mb_strpos
があり、同様に mb_str_contains
も必要なのではないでしょうか。
実際、内部メーリングリストの議論を見ると、「UTF-8 ではちゃんと動くが Shift_JIS では動かないのでは?」という 意見もあり、怪しい気がします。2
This is not true for all character encodings. For UTF-8 it is correct,
but consider for example the Japanese encoding Shift_JIS, where the
second byte of a multi-byte character can be a valid first byte of a
single-byte character. str_contains() would have incorrect behaviour for
this case.
日本語対応にやや懸念は残るものの、他の言語には普通に備わっている関数が PHP にも追加されること自体は良いことなのではないか、と思います。
内部メーリングリストの議論を見ると、
str_starts_with
やstr_ends_with
を追加する RFCが最初から大文字小文字の区別やマルチバイト版を用意した結果、否決されてしまったショックが大きいようです。 ↩これに対して、 Nikita Popov が 返答していますが、 "That's of course true, but I consider it ultimately unimportant." と一蹴されちゃっています(苦笑) なんとなく「細かいことはあとでいいから、とりあえず導入したいんだよ!」という雰囲気を感じます。この辺の議論は内部実装の話になっていて、あまり理解できている自信がありませんが。 ↩