RFC: array_str_contains
- Author: Sepehr Mahmoudi, sepehrphpr@gmail.com
- Status: Under Discussion
- First Published at: 2026-08-22
- Target PHP Version: PHP 8.7
- Version: 0.4
Introduction
Finding elements in an array that contain a specific substring is a very common task in PHP. Currently, developers must rely on array_filter() combined with a userland closure and str_contains(), or write a custom foreach loop.
Executing a userland callback for every element in a large array using array_filter() introduces unnecessary performance overhead. This RFC proposes a native C function, array_str_contains(), to perform this task efficiently, eliminating the closure overhead and providing a much cleaner, more readable syntax.
Proposal
This RFC proposes the addition of a new array function:
function array_str_contains( array $haystack, string $needle ): array {}
Parameters:
$haystack: The input array to be searched.$needle: The substring to search for within the array values.
The function searches for the exact substring $needle in the values of the $haystack. It returns a new array containing only the matched elements.
- The search is case-sensitive (consistent with the behavior of
str_contains) and performs a strict byte-for-byte comparison. - By matching exact byte sequences natively in C, it provides full, highly efficient support for UTF-8 characters, non-Latin scripts, and emojis out of the box, without relying on
ext/intlor incurring any ICU overhead. - Non-string values in the array are implicitly cast to strings before the check.
- Original array keys are preserved in the returned array.
Use Cases
This function simplifies many common filtering tasks, including but not limited to:
- File filtering: Filtering a list of filenames or paths to find specific extensions (e.g.,
.phpor.jpg). - Log analysis: Searching an array of log lines to extract entries containing specific keywords like
“ERROR”or“Warning”. - Multilingual & Emoji Data Processing: Safely and efficiently filtering datasets containing UTF-8 text (like Japanese, Persian, Arabic) or emojis, because the search operates strictly on exact byte sequences rather than requiring Unicode-aware decoding.
- Data processing: Filtering a dataset of URLs, URIs, or text snippets for a specific substring without writing verbose closures.
Why a native function instead of array_filter?
While the same result can be achieved using array_filter() combined with a closure and str_contains(), a native array_str_contains() function provides better ergonomics and cleaner syntax. Furthermore, a native C implementation eliminates the overhead of repeatedly calling closures and context switching for each array element, which can be highly beneficial when processing large arrays or performing heavy log and data analysis.
Examples
Example 1: Basic Substring Search
// When working with a list of URLs, you might want to extract only the links related to a specific section, such as products. $urls = [ 0 => 'https://example.com/products/laptops', 1 => 'https://example.com/about-us', 2 => 'https://example.com/products/phones', 3 => 'https://example.com/contact' ]; $result = array_str_contains($urls, 'products'); /* Returns: [ 0 => 'https://example.com/products/laptops', 2 => 'https://example.com/products/phones' ] */
Explanation: The function searches for the exact substring 'products' within the array of URLs. It is case-sensitive, so uppercase variations like 'Products' are not matched. The original array keys are strictly preserved in the returned array.
Example 2: Searching in Log Lines
$logs = [ 200 => 'INFO: Application started', 201 => 'ERROR: Database timeout', 202 => 'WARNING: CPU load high', 203 => 'ERROR: Invalid user input' ]; $errors = array_str_contains($logs, 'ERROR:'); print_r($errors); /* Output: Array ( [201] => ERROR: Database timeout [203] => ERROR: Invalid user input ) */
Explanation: This example demonstrates filtering a list of log messages to easily extract the lines containing the “ERROR:” substring. Custom keys are maintained in the result.
Example 3: Handling Non-String Values
$data = [ 'user_100', 100, 10055, 'guest', true ]; $matches = array_str_contains($data, '100'); print_r($matches); /* Output: Array ( [0] => user_100 [1] => 100 [2] => 10055 ) */
Explanation: Non-string values are implicitly cast to strings before the comparison. For instance, the integer 100 becomes the string “100”, which successfully matches the needle “100”.
Example 4: UTF-8, Multilingual and Emoji Support
$messages = [ 'msg1' => 'Hello world! 🌍', 'msg2' => 'こんにちは、Yuyaさん', // Japanese: Hello, Yuya-san 'msg3' => 'سلام دنیا', 'msg4' => 'こんにちは、世界', // Japanese: Hello, World ]; $japanese_matches = array_str_contains($messages, 'こんにちは'); /* Returns: [ 'msg2' => 'こんにちは、Yuyaさん', 'msg4' => 'こんにちは、世界' ] */ $emoji_matches = array_str_contains($messages, '🌍'); /* Returns: [ 'msg1' => 'Hello world! 🌍' ] */
Explanation: Because the function matches exact byte sequences natively in C, it flawlessly supports UTF-8 characters (like Japanese and Persian) and emojis without requiring any extra configuration, extensions, or Unicode decoding.
Polyfill / Userland Equivalent
The behavior of the proposed function can be illustrated by the following userland implementation. (Note: This approach uses a standard loop to avoid the closure overhead typical of array_filter()):
<?php function array_str_contains(array $haystack, string $needle): array { $result = []; foreach ($haystack as $key => $value) { // Cast to string to handle non-string values safely, matching str_contains behavior if (str_contains((string) $value, $needle)) { $result[$key] = $value; } } return $result; }
Behavior with Numeric & Mixed Values
`array_str_contains()` gracefully handles scalar numeric values (integers and floats) alongside strings without throwing type errors, making it robust for real-world data processing (e.g., database records, product IDs, or mixed logs).
Example 1: Basic Mixed Types
$items = ["user_101", 2048, "order_105", 300, "item_20"]; // Searching for "10" matches both string codes and numeric values $result1 = array_str_contains($items, "10"); var_dump($result1); // Output: ["user_101", "order_105"] // Searching for "20" matches the integer 2048 and the string "item_20" $result2 = array_str_contains($items, "20"); var_dump($result2); // Output: [2048, "item_20"]
Example 2: Practical E-Commerce Product Code Filtering
$product_skus = [ "SKU-2026-X", 20260115, // Integer timestamp/batch ID "PROD-9902", 2026998, // Numeric serial number "ACCESSORY-12" ]; // Easily find all items belonging to batch "2026" $batch_2026 = array_str_contains($product_skus, "2026"); var_dump($batch_2026); // Output: ["SKU-2026-X", 20260115, 2026998]
Backward Incompatible Changes
None.
Proposed PHP Version(s)
Next minor version (PHP 8.7).
RFC Impact
- SAPIs: No impact.
- Existing Extensions: No impact.
- Opcache: No impact.
Open Issues
None at this time.
Proposed Voting Choices
State whether to accept the RFC and merge the patch into PHP 8.6. As this is a standard feature addition, it requires a 2/3 majority to pass.
Implementation
In Progress (TBD).