LoginSignup
10
5

More than 3 years have passed since last update.

PHP8にstr_contains関数が追加されることになったというお話

Last updated at Posted at 2020-03-08

strposstrstr を使わずに済むようになる・・・かもしれません( 日本語対応にやや懸念あり )。

以下、 RFC をもとに紹介します。

まだ投票中ですが、3月8日現在、賛成42/反対5という圧倒的多数の支持を得ているため、追加される公算が高いです。

既存関数の問題点

ある文字列が別の文字列に含まれているかをチェックする際、これまで strposstrstr といった関数が使われてきました。

しかし、これらの関数は、以下の問題を抱えています。

  • 読み手にとってあまり直感的でない
  • 間違いやすい
  • 新しく PHP に触れる開発者にとって覚えにくい

そのため、多くの PHP フレームワークが、同様の振る舞いをするヘルパー関数を提供しています。それだけ、この機能は、重要だし、必要とされているということです。

提案

概要

str_contains ( string $haystack , string $needle ) : bool

$needle$haystack に含まれているかをチェックし、$needle が見つかったかを真偽値( true/false )で返します。

例えば、以下のようになります。

str_contains("abc", "a"); // true
str_contains("abc", "d"); // false

// $needle が空文字だった場合
str_contains("abc", "");  // true
str_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 にも追加されること自体は良いことなのではないか、と思います。


  1. 内部メーリングリストの議論を見ると、 str_starts_withstr_ends_with を追加する RFC が最初から大文字小文字の区別やマルチバイト版を用意した結果、否決されてしまったショックが大きいようです。  

  2. これに対して、 Nikita Popov が 返答 していますが、 "That's of course true, but I consider it ultimately unimportant." と一蹴されちゃっています(苦笑) なんとなく「細かいことはあとでいいから、とりあえず導入したいんだよ!」という雰囲気を感じます。この辺の議論は内部実装の話になっていて、あまり理解できている自信がありませんが。 

10
5
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
10
5