Table of Contents

PHP RFC: array_match

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

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:

Examples

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

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