====== PHP RFC: array_match ======
* **Version:** 0.1
* **Date:** 2026-08-22
* **Author:** Sepehr Mahmoudi, sepehrphpr@gmail.com
* **Status:** Draft
* **Target Version:** PHP 8.7
* **Implementation:** In Progress (TBD)
===== Introduction =====
Searching for a specific substring within an array of strings is a very common operation in PHP applications. Currently, developers must rely on ''array_filter()'' combined with a closure containing ''strpos()'' or ''str_contains()''. This approach, while functional, introduces significant overhead due to the execution of userland closures for every element in the array.
This RFC proposes the introduction of a new function, ''array_match()'', which performs this operation natively in C. This provides a simpler, more readable syntax and significantly improves performance by avoiding userland function call overhead.
===== Proposal =====
Introduce a new standard library function ''array_match()''.
==== Function Signature ====
function array_match(
array $array,
string $needle,
bool $ignore_case = false
): array {}
==== Parameters ====
* **$array**: The input array to be searched.
* **$needle**: The substring to search for within the array values.
* **$ignore_case**: If set to ''true'', the search will be case-insensitive (similar to ''stripos''). If ''false'' (default), the search is case-sensitive (similar to ''strpos'').
**Note:** The function preserves the original keys of the array in the returned result. Non-string values in the array are safely cast to strings during the evaluation, or can be skipped depending on the final internal implementation choice.
===== Use Cases =====
The primary use cases for ''array_match()'' revolve around developer experience (DX) and performance:
* **Log Filtering:** Quickly extracting relevant log messages containing a specific error code or keyword from a large array of log lines.
* **File/Directory Searches:** Filtering an array of filenames or paths by a specific extension or partial name (e.g., finding all ".php" files in a scanned directory array).
* **Data Processing:** Searching through user inputs, database text dumps, or API responses where data is represented as an array of strings.
* **Performance Optimization:** Replacing heavily iterated ''array_filter'' + closure combinations in performance-critical loops with a single, highly optimized native C function.
===== Examples =====
==== Example 1: Case-sensitive search ====
$files = [
'doc1.txt',
'image.PNG',
'script.php',
'index.PHP',
'readme.md'
];
$result = array_match(
$files,
'.php'
);
print_r($result);
/* Output:
Array
(
[2] => script.php
)
*/
In this example, the function searches for the exact string ''.php''. Since the ''$ignore_case'' parameter is ''false'' by default, it performs a case-sensitive search. It only matches ''script.php'' and ignores ''index.PHP''.
==== Example 2: Case-insensitive search ====
$files = [
'doc1.txt',
'image.PNG',
'script.php',
'index.PHP',
'readme.md'
];
$result = array_match(
$files,
'.php',
true
);
print_r($result);
/* Output:
Array
(
[2] => script.php
[3] => index.PHP
)
*/
By setting the ''$ignore_case'' parameter to ''true'', the function performs a case-insensitive search. It successfully matches both ''.php'' and ''.PHP'', returning both ''script.php'' and ''index.PHP'' while preserving their original array keys.
===== Polyfill / Userland Equivalent =====
To demonstrate the exact behavior and to show how developers achieve this currently (without closure overhead), here is the userland equivalent using a ''foreach'' loop.
This polyfill highlights why a native implementation is beneficial: it removes the need for developers to write boilerplate loops for such a trivial and common task.
function array_match_polyfill(
array $array,
string $needle,
bool $ignore_case = false
): array {
$result = [];
foreach ($array as $key => $value) {
// Cast to string to ensure safe searching
$stringValue = (string) $value;
if ($ignore_case) {
if (stripos($stringValue, $needle) !== false) {
$result[$key] = $value;
}
} else {
if (strpos($stringValue, $needle) !== false) {
$result[$key] = $value;
}
}
}
return $result;
}