[RFC] [Discussion] array_str_contains() for PHP 8.7

php.internals

سپهر محمودی

2 days ago
Hi everyone, I'd like to start the discussion for a new RFC proposing the `array_str_contains()` function for PHP 8.7. Filtering arrays based on substring matching is something many of us write on a regular basis, usually with boilerplate like: $matches = array_filter($array, fn($item) => is_string($item) && str_contains($item, $needle)); This RFC proposes adding a native `array_str_contains(array $haystack, string $needle): array` to the standard library to make this faster, cleaner, and memory-efficient while preserving array keys. You can check out the RFC and implementation details here: - RFC: https://wiki.php.net/rfc/array_str_contains - Pull Request: https://github.com/php/php-src/pull/23512 I'd really appreciate your feedback, thoughts, and suggestions. Please keep all feedback and replies in this mailing list thread so we have everything in one place. Thanks, Sepehr

Seifeddine Gmati

1 day ago
On Sun, 30 Aug 2026 at 15:19, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬
> > Hi everyone, > > I'd like to start the discussion for a new RFC proposing the `array_str_contains()` function for PHP 8.7.
Hi Sepehr,
> Filtering arrays based on substring matching is something many of us write on a regular basis, usually with boilerplate like: > $matches = array_filter($array, fn($item) => is_string($item) && str_contains($item, $needle));
I don't recall ever writing something like this. If I did, not remembering it suggests it isn't that common. The RFC also does not include any proof of the "regular basis", and under same conditions, the same case could be made for array_str_starts_with, array_str_ends_with, array_preg_match, array_str_length, and probably few more hunder combinations, I really don't see how `str_contains` is in any way special. The name `array_str_contains` is also confusing, it does not tell me what this function is doing, there is nothing indicating that it is filtering. `array_str_contains($arr, $str)` could mean that every string is joined with `$str` so by the end all string entries in `$arr` do contain `$str`? Idk.
> Thanks, > Sepehr
Cheers, Seifeddine.

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۰:۵۸ Seifeddine Gmati <azjezz@carthage.software> نوشت:
> On Sun, 30 Aug 2026 at 15:19, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > > > > Hi everyone, > > > > I'd like to start the discussion for a new RFC proposing the > `array_str_contains()` function for PHP 8.7. > > Hi Sepehr, > > > Filtering arrays based on substring matching is something many of us > write on a regular basis, usually with boilerplate like: > > $matches = array_filter($array, fn($item) => is_string($item) && > str_contains($item, $needle)); > > I don't recall ever writing something like this. If I did, not > remembering it suggests it isn't that common. > > The RFC also does not include any proof of the "regular basis", and > under same conditions, the same case could be made for > array_str_starts_with, array_str_ends_with, array_preg_match, > array_str_length, and probably few more hunder combinations, I really > don't see how `str_contains` is in any way special. > > The name `array_str_contains` is also confusing, it does not tell me > what this function is doing, there is nothing indicating that it is > filtering. `array_str_contains($arr, $str)` could mean that every > string is joined with `$str` so by the end all string entries in > `$arr` do contain `$str`? Idk. > > > Thanks, > > Sepehr > > Cheers, > Seifeddine. >
-------- Hi Seifeddine, Thank you for your feedback and perspective! Regarding the use-case and frequency: Sub-string filtering on lists of strings is a very common task across many domains — such as autocomplete suggestions, filtering file/directory lists, simple search filters over tag/category arrays, and processing logs or URL lists. While `array_filter` with a closure can achieve this, it introduces noticeable overhead in userland due to repeated closure invocations and type checks on every element. Implementing this natively in C provides direct memory traversal and immediate performance gains for a very frequent real-world operation. Regarding other variants (`starts_with`, `ends_with`, etc.): `str_contains` is arguably the most general and widely-used substring operation. However, discussing whether a broader set of string-array utilities or a more specific naming convention makes sense is exactly why this RFC is in discussion. Regarding the naming (`array_str_contains`): You raise a fair point about clarity. Some developers might intuitively expect a boolean return type (similar to `in_array` or `str_contains`) or wonder if it acts as a filter. Alternative names like `array_filter_contains()` or `array_grep()`-style semantics could also be considered if the community prefers more explicit filtering terminology. I appreciate your insights and look forward to hearing more thoughts from the internals community on both the concept and the ideal naming. Best regards, Sepehr

Seifeddine Gmati

1 day ago
‪On Sun, 30 Aug 2026 at 23:20, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬
> > > > در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۰:۵۸ Seifeddine Gmati <azjezz@carthage.software> نوشت: >> >> On Sun, 30 Aug 2026 at 15:19, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬ >> > >> > Hi everyone, >> > >> > I'd like to start the discussion for a new RFC proposing the `array_str_contains()` function for PHP 8.7. >> >> Hi Sepehr, >> >> > Filtering arrays based on substring matching is something many of us write on a regular basis, usually with boilerplate like: >> > $matches = array_filter($array, fn($item) => is_string($item) && str_contains($item, $needle)); >> >> I don't recall ever writing something like this. If I did, not >> remembering it suggests it isn't that common. >> >> The RFC also does not include any proof of the "regular basis", and >> under same conditions, the same case could be made for >> array_str_starts_with, array_str_ends_with, array_preg_match, >> array_str_length, and probably few more hunder combinations, I really >> don't see how `str_contains` is in any way special. >> >> The name `array_str_contains` is also confusing, it does not tell me >> what this function is doing, there is nothing indicating that it is >> filtering. `array_str_contains($arr, $str)` could mean that every >> string is joined with `$str` so by the end all string entries in >> `$arr` do contain `$str`? Idk. >> >> > Thanks, >> > Sepehr >> >> Cheers, >> Seifeddine. > > > -------- > Hi Seifeddine, > > Thank you for your feedback and perspective!
Hi again.
> > Regarding the use-case and frequency: > Sub-string filtering on lists of strings is a very common task across many domains — such as autocomplete suggestions, filtering file/directory lists, simple search filters over tag/category arrays, and processing logs or URL lists.
Do you have any numbers to support this? Did you run an analysis on open-source projects?
> While `array_filter` with a closure can achieve this, it introduces noticeable overhead in userland due to repeated closure invocations and type checks on every element. Implementing this natively in C provides direct memory traversal and immediate performance gains for a very frequent real-world operation.
This can be said about any existing function that takes a callable, and any other callable, e.g., `array_map` + `str_rot13`. Or again, any other 2 functions fitting the description. I still don't see why the combination of array_filter + str_contains is special.
> Regarding other variants (`starts_with`, `ends_with`, etc.): > `str_contains` is arguably the most general and widely-used substring operation. However, discussing whether a broader set of string-array utilities or a more specific naming convention makes sense is exactly why this RFC is in discussion.
I wasn't advocating for adding more to this RFC; I'm saying that this function is redundant. It makes no sense to have it as part of the stdlib.
> Best regards, > Sepehr
Cheers.

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۲:۲۸ Seifeddine Gmati <azjezz@carthage.software> نوشت:
> ‪On Sun, 30 Aug 2026 at 23:20, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > > > > > > > > در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۰:۵۸ Seifeddine Gmati > <azjezz@carthage.software> نوشت: > >> > >> On Sun, 30 Aug 2026 at 15:19, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > >> > > >> > Hi everyone, > >> > > >> > I'd like to start the discussion for a new RFC proposing the > `array_str_contains()` function for PHP 8.7. > >> > >> Hi Sepehr, > >> > >> > Filtering arrays based on substring matching is something many of us > write on a regular basis, usually with boilerplate like: > >> > $matches = array_filter($array, fn($item) => is_string($item) && > str_contains($item, $needle)); > >> > >> I don't recall ever writing something like this. If I did, not > >> remembering it suggests it isn't that common. > >> > >> The RFC also does not include any proof of the "regular basis", and > >> under same conditions, the same case could be made for > >> array_str_starts_with, array_str_ends_with, array_preg_match, > >> array_str_length, and probably few more hunder combinations, I really > >> don't see how `str_contains` is in any way special. > >> > >> The name `array_str_contains` is also confusing, it does not tell me > >> what this function is doing, there is nothing indicating that it is > >> filtering. `array_str_contains($arr, $str)` could mean that every > >> string is joined with `$str` so by the end all string entries in > >> `$arr` do contain `$str`? Idk. > >> > >> > Thanks, > >> > Sepehr > >> > >> Cheers, > >> Seifeddine. > > > > > > -------- > > Hi Seifeddine, > > > > Thank you for your feedback and perspective! > > Hi again. > > > > > Regarding the use-case and frequency: > > Sub-string filtering on lists of strings is a very common task across > many domains — such as autocomplete suggestions, filtering file/directory > lists, simple search filters over tag/category arrays, and processing logs > or URL lists. > > Do you have any numbers to support this? Did you run an analysis on > open-source projects? > > > While `array_filter` with a closure can achieve this, it introduces > noticeable overhead in userland due to repeated closure invocations and > type checks on every element. Implementing this natively in C provides > direct memory traversal and immediate performance gains for a very frequent > real-world operation. > > This can be said about any existing function that takes a callable, > and any other callable, e.g., `array_map` + `str_rot13`. Or again, any > other 2 functions fitting the description. I still don't see why the > combination of array_filter + str_contains is special. > > > Regarding other variants (`starts_with`, `ends_with`, etc.): > > `str_contains` is arguably the most general and widely-used substring > operation. However, discussing whether a broader set of string-array > utilities or a more specific naming convention makes sense is exactly why > this RFC is in discussion. > > I wasn't advocating for adding more to this RFC; I'm saying that this > function is redundant. It makes no sense to have it as part of the > stdlib. > > > Best regards, > > Sepehr > > Cheers. >
----------- Hi Saif, Thanks for the follow-up and the tough questions. 1. Regarding data and open-source analysis: You make a valid point about backing this up with concrete data. During this 14-day discussion period, I will run static analysis across top Packagist/GitHub packages (looking for patterns matching array_filter with str_contains/stripos closures) and update the RFC with empirical frequency data. 2. Regarding composability vs dedicated helpers: Comparing fundamental substring filtering to niche combinations like `array_map` + `str_rot13` isn't entirely an apples-to-apples comparison. Substring matching across collections is a ubiquitous, everyday task in web development (handling URL routes, file path filtering, tagging systems, autocomplete candidate lists, etc.). PHP has historically added focused, highly-optimized standard functions where the pattern is so overwhelmingly common that saving closure allocations, call frame overhead, and boilerplate significantly improves DX and execution speed. 3. Redundancy and stdlib scope: I completely understand your stance regarding keeping the standard library lean and relying on userland composition. Finding the right balance between minimal stdlib and developer ergonomics is precisely what the discussion and voting phases are meant to evaluate. I appreciate your critical feedback—it helps refine the RFC and ensures we substantiate the proposal with concrete metrics before voting. Best regards, Sepehr

Weirdan

1 day ago
Hi سپهر ‪On Mon, Aug 31, 2026 at 12:21 AM ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬
> While `array_filter` with a closure can achieve this, it introduces > noticeable overhead in userland due to repeated closure invocations and > type checks on every element. > >>
If this overhead could be reduced, it would improve the performance of any built-in function that calls a user-land closure, not limited to the array_filter + str_contains combo. Have you considered solving this problem instead, at least for closures generated by partial applications of built-in functions?
-- Best regards, Bruce Weirdan mailto: weirdan@gmail.com

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۶:۳۲ Bruce Weirdan <weirdan@gmail.com> نوشت:
> Hi سپهر > > ‪On Mon, Aug 31, 2026 at 12:21 AM ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > >> While `array_filter` with a closure can achieve this, it introduces >> noticeable overhead in userland due to repeated closure invocations and >> type checks on every element. >> >>> > If this overhead could be reduced, it would improve the performance of any > built-in function that calls a user-land closure, not limited to the > array_filter + str_contains combo. Have you considered solving this problem > instead, at least for closures generated by partial applications of > built-in functions? > > -- > Best regards, > Bruce Weirdan mailto: > weirdan@gmail.com >
-------- Hi Bruce, Thanks for the reply. You're right that the closure invocation overhead is not specific to array_filter + str_contains — it applies to any builtin that calls a userland callable. However, I see these as complementary rather than mutually exclusive approaches. Optimizing closure invocation for partial applications is a deep change in the engine (VM loop, call frames, possibly JIT/inline caching), and would only benefit closures created from first-class callable syntax. Even then, the userland code would remain more verbose, and the engine would still have to materialize a call frame per element. A dedicated function avoids the call overhead entirely with a few lines of straightforward C, keeps userland code short and readable, and is shippable now rather than being tied to a long-term engine project. That said, I'd be genuinely interested in seeing a proposal for optimizing first-class callable invocation — I think it would benefit array_map/array_filter users broadly. But I don't think it should block a small, pragmatic stdlib addition. Best regards, Sepehr

Kamil Tekiela

1 day ago
‪On Mon, 31 Aug 2026 at 14:26, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬
> > > > در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۶:۳۲ Bruce Weirdan <weirdan@gmail.com> نوشت: >> >> Hi سپهر >> >> ‪On Mon, Aug 31, 2026 at 12:21 AM ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> wrote:‬ >>> >>> While `array_filter` with a closure can achieve this, it introduces noticeable overhead in userland due to repeated closure invocations and type checks on every element. >> >> >> If this overhead could be reduced, it would improve the performance of any built-in function that calls a user-land closure, not limited to the array_filter + str_contains combo. Have you considered solving this problem instead, at least for closures generated by partial applications of built-in functions? >> >> -- >> Best regards, >> Bruce Weirdan mailto:weirdan@gmail.com > > -------- > > Hi Bruce, > > Thanks for the reply. > > You're right that the closure invocation overhead is not specific to > array_filter + str_contains — it applies to any builtin that calls a > userland callable. However, I see these as complementary rather than > mutually exclusive approaches. > > Optimizing closure invocation for partial applications is a deep change > in the engine (VM loop, call frames, possibly JIT/inline caching), and > would only benefit closures created from first-class callable syntax. > Even then, the userland code would remain more verbose, and the engine > would still have to materialize a call frame per element. > > A dedicated function avoids the call overhead entirely with a few lines > of straightforward C, keeps userland code short and readable, and is > shippable now rather than being tied to a long-term engine project. > > That said, I'd be genuinely interested in seeing a proposal for > optimizing first-class callable invocation — I think it would benefit > array_map/array_filter users broadly. But I don't think it should block > a small, pragmatic stdlib addition. > > Best regards, > Sepehr >
Hi Sepehr, In terms of performance, what numbers are we speaking of here? First-class callables have already been significantly improved in recent versions of PHP. How much difference is there from a dedicated function? I would rather see array_filter with a callable than a dedicated function. It's more understandable to me that way. Also, I agree with what others said that I don't consider this code pattern to be exceptionally popular to warrant a dedicated optimized function in the language. I have never found that to be a performance issue in any project. Regards, Kamil

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۷:۱۶ Kamil Tekiela <tekiela246@gmail.com> نوشت:
> ‪On Mon, 31 Aug 2026 at 14:26, ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > > > > > > > > در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۶:۳۲ Bruce Weirdan <weirdan@gmail.com> > نوشت: > >> > >> Hi سپهر > >> > >> ‪On Mon, Aug 31, 2026 at 12:21 AM ‫سپهر محمودی‬‎ <sepehrphpr@gmail.com> > wrote:‬ > >>> > >>> While `array_filter` with a closure can achieve this, it introduces > noticeable overhead in userland due to repeated closure invocations and > type checks on every element. > >> > >> > >> If this overhead could be reduced, it would improve the performance of > any built-in function that calls a user-land closure, not limited to the > array_filter + str_contains combo. Have you considered solving this problem > instead, at least for closures generated by partial applications of > built-in functions? > >> > >> -- > >> Best regards, > >> Bruce Weirdan mailto: > weirdan@gmail.com > > > > -------- > > > > Hi Bruce, > > > > Thanks for the reply. > > > > You're right that the closure invocation overhead is not specific to > > array_filter + str_contains — it applies to any builtin that calls a > > userland callable. However, I see these as complementary rather than > > mutually exclusive approaches. > > > > Optimizing closure invocation for partial applications is a deep change > > in the engine (VM loop, call frames, possibly JIT/inline caching), and > > would only benefit closures created from first-class callable syntax. > > Even then, the userland code would remain more verbose, and the engine > > would still have to materialize a call frame per element. > > > > A dedicated function avoids the call overhead entirely with a few lines > > of straightforward C, keeps userland code short and readable, and is > > shippable now rather than being tied to a long-term engine project. > > > > That said, I'd be genuinely interested in seeing a proposal for > > optimizing first-class callable invocation — I think it would benefit > > array_map/array_filter users broadly. But I don't think it should block > > a small, pragmatic stdlib addition. > > > > Best regards, > > Sepehr > > > > Hi Sepehr, > > In terms of performance, what numbers are we speaking of here? > First-class callables have already been significantly improved in > recent versions of PHP. How much difference is there from a dedicated > function? > > I would rather see array_filter with a callable than a dedicated > function. It's more understandable to me that way. Also, I agree with > what others said that I don't consider this code pattern to be > exceptionally popular to warrant a dedicated optimized function in the > language. I have never found that to be a performance issue in any > project. > > Regards, > Kamil >
---------- Hi Kamil, Thank you for your feedback and valid points! Regarding performance: Even with the great improvements to first-class callables and engine call overhead in recent PHP versions, there are two key architectural differences here: 1. Short-circuiting vs Allocation: Using `array_filter` processes the entire array and allocates a new filtered array in memory, whereas a dedicated C implementation (`array_str_contains` / short-circuit loop) immediately returns `true` on the first match without extra allocations. 2. Direct C-level loop: Bypassing the VM dispatch loop for each element gives noticeable gains, especially on larger datasets or hot paths. I am currently preparing detailed benchmark comparisons across different dataset sizes (small, medium, large, and early vs late match scenarios) to include concrete numbers in the RFC draft. Regarding readability and utility: Similar to how `str_contains()` simplified `strpos() !== false` or how `array_all()` / `array_any()` were introduced to avoid boilerplate, the motivation here is to provide a clean, self-describing standard utility that avoids writing manual loops or memory-allocating filter chains. That being said, collecting diverse community perspectives like yours is exactly why we're discussing this early, and I'll make sure the performance data and use cases are clearly demonstrated in the RFC. Best regards, Sepehr

Kamil Tekiela

1 day ago
> 1. Short-circuiting vs Allocation: Using `array_filter` processes the entire array and allocates a new filtered array in memory, whereas a dedicated C implementation (`array_str_contains` / short-circuit loop) immediately returns `true` on the first match without extra allocations.
What do you mean? I thought the purpose of the new function was to return a list with all matching entries? How could it short-circuit on the first match?
> 2. Direct C-level loop: Bypassing the VM dispatch loop for each element gives noticeable gains, especially on larger datasets or hot paths.
What kind of dispatch are you talking about here? Do you mean calling str_contains() for each row?

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۹:۲۲ Kamil Tekiela <tekiela246@gmail.com> نوشت:
> > 1. Short-circuiting vs Allocation: Using `array_filter` processes the > entire array and allocates a new filtered array in memory, whereas a > dedicated C implementation (`array_str_contains` / short-circuit loop) > immediately returns `true` on the first match without extra allocations. > > What do you mean? I thought the purpose of the new function was to > return a list with all matching entries? How could it short-circuit on > the first match? > > > 2. Direct C-level loop: Bypassing the VM dispatch loop for each element > gives noticeable gains, especially on larger datasets or hot paths. > > What kind of dispatch are you talking about here? Do you mean calling > str_contains() for each row? >
-------- Hi Kamil, Thanks for pointing that out, and apologies for the confusion in my previous wording! 1. You are totally right: the function returns an array of matched elements (filtering), so it does iterate through the full array rather than short-circuiting. My previous note mistakenly mixed up the behavior with an existence-check helper like array_any(). The main benefit here is avoiding userland closure invocation overhead for each element. 2. Exactly, by VM dispatch / call overhead, I meant the overhead of repeatedly calling userland closures or functions (like invoking str_contains() per element via array_filter()) compared to running a native C loop using php_memnstr directly. Best regards, Sepehr

Tim Düsterhus

1 day ago
Hi On 2026-08-30 16:19, سپهر محمودی wrote:
> You can check out the RFC and implementation details here: > - RFC: https://wiki.php.net/rfc/array_str_contains > - Pull Request: https://github.com/php/php-src/pull/23512
Don’t forget to add your RFC to the overview at https://wiki.php.net/rfc. As for the proposal itself, I agree with the existing replies that I don’t consider this to be a useful addition to PHP’s stdlib. See also my reply in the discussion thread about whether or not RFCs should include polyfills: https://news-web.php.net/php.internals/132402 Best regards Tim Düsterhus

سپهر محمودی

1 day ago
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۸:۴۲ Tim Düsterhus <tim@bastelstu.be> نوشت:
> Hi > > On 2026-08-30 16:19, سپهر محمودی wrote: > > You can check out the RFC and implementation details here: > > - RFC: https://wiki.php.net/rfc/array_str_contains > > - Pull Request: https://github.com/php/php-src/pull/23512 > > Don’t forget to add your RFC to the overview at > https://wiki.php.net/rfc. > > As for the proposal itself, I agree with the existing replies that I > don’t consider this to be a useful addition to PHP’s stdlib. See also my > reply in the discussion thread about whether or not RFCs should include > polyfills: https://news-web.php.net/php.internals/132402 > > Best regards > Tim Düsterhus >
-------- Hi Tim, Thanks for the reminder! I will add the RFC to the overview page shortly. I also appreciate your feedback and insight regarding standard library additions. I understand the perspective of keeping the stdlib concise and relying on composable primitives like array_any(). Best regards, Sepehr