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

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:

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

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.

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۰:۵۸ 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

‪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.

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۰۲:۲۸ 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

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

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۶:۳۲ Bruce Weirdan <weirdan@gmail.com> نوشت:

···

Best regards,
Bruce Weirdan mailto:weirdan@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

On 2026-08-30 16:19, سپهر محمودی wrote:

You can check out the RFC and implementation details here:
- RFC: PHP: rfc:array_str_contains
- Pull Request: Add array_str_contains() function to standard library by sepehrphpr · Pull Request #23512 · php/php-src · GitHub

Don’t forget to add your RFC to the overview at PHP: 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: php.internals: Re: [DISCUSS] Should RFCs for new functions include a userland polyfill/reference implementation?

Best regards
Tim Düsterhus

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۷:۱۶ 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

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?

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۹:۲۲ 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?

  1. 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 <tim@bastelstu.be> نوشت:

Hi

On 2026-08-30 16:19, سپهر محمودی wrote:

You can check out the RFC and implementation details here:

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

Hi everyone,

I’m following up on the array_str_contains() RFC and would appreciate any feedback, especially regarding the proposed API and the real-world usage analysis.

The updated analysis shows that array_str_contains() can simplify up to 17 of the 32 identified patterns, while the remaining patterns contain additional logic and are not direct replacements.

The CI test issue is being addressed separately by correcting the expected output in the .phpt test.

Thanks for taking the time to review the proposal.

Best regards,
Sepehr

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۹:۵۲ سپهر محمودی <sepehrphpr@gmail.com> نوشت:

در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۸:۴۲ Tim Düsterhus <tim@bastelstu.be> نوشت:

Hi

On 2026-08-30 16:19, سپهر محمودی wrote:

You can check out the RFC and implementation details here:

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

Hi

On 8/31/26 18:22, سپهر محمودی wrote:

Thanks for the reminder! I will add the RFC to the overview page shortly.

It appears this hasn't happened yet.

Best regards
Tim Düsterhus