====== 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; }