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
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 howstr_containsis in any way special.The name
array_str_containsis 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$strso by the end all string entries in
$arrdo contain$str? Idk.Thanks,
SepehrCheers,
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 howstr_containsis in any way special.The name
array_str_containsis 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$strso by the end all string entries in
$arrdo contain$str? Idk.Thanks,
SepehrCheers,
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_filterwith 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_containsis 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 howstr_containsis in any way special.The name
array_str_containsis 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$strso by the end all string entries in
$arrdo contain$str? Idk.Thanks,
SepehrCheers,
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_filterwith 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_containsis 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,
SepehrCheers.
Hi Saif,
Thanks for the follow-up and the tough questions.
-
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. -
Regarding composability vs dedicated helpers:
Comparing fundamental substring filtering to niche combinations like
array_map+str_rot13isn'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. -
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_filterwith 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 نوشت:
Hi سپهر
On Mon, Aug 31, 2026 at 12:21 AM سپهر محمودی sepehrphpr@gmail.com
wrote:While
array_filterwith 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
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_filterwith 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
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۷:۱۶ 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_filterwith 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,
SepehrHi 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:
- Short-circuiting vs Allocation: Using
array_filterprocesses the
entire array and allocates a new filtered array in memory, whereas a
dedicated C implementation (array_str_contains/ short-circuit loop)
immediately returnstrueon the first match without extra allocations. - 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
- Short-circuiting vs Allocation: Using
array_filterprocesses the entire array and allocates a new filtered array in memory, whereas a dedicated C implementation (array_str_contains/ short-circuit loop) immediately returnstrueon 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?
- 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
نوشت:
- Short-circuiting vs Allocation: Using
array_filterprocesses the
entire array and allocates a new filtered array in memory, whereas a
dedicated C implementation (array_str_contains/ short-circuit loop)
immediately returnstrueon 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?
- 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!
-
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 likearray_any(). The main benefit here is avoiding
userland closure invocation overhead for each element. -
Exactly, by VM dispatch / call overhead, I meant the overhead of
repeatedly calling userland closures or functions (like invoking
str_contains()per element viaarray_filter()) compared to running a native
C loop using php_memnstr directly.
Best regards,
Sepehr
Hi
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
در تاریخ دوشنبه ۳۱ اوت ۲۰۲۶، ۱۸:۴۲ Tim Düsterhus tim@bastelstu.be نوشت:
Hi
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/132402Best 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