I need to filter my flat, associative array of string-type values by checking if its key is found (case-sensitive) in its value as a substring. In other words, if an element's key is in the element's value, I want to retain the element in the output array.
I can craft a classic foreach()
loop with calls of strpos()
, but this feels very pedestrian. Is there a more modern/elegant way do this?
My code:
$array = [
'needle' => 'needle in haystack text',
'Need' => 'another needle',
'fine' => 'refined',
'found' => 'Foundation',
'' => 'non-empty haystack',
'missing' => 'not here',
'This is 0 in a haystack!',
];
$result = [];
foreach ($array as $needle => $haystack) {
if (strpos($haystack, $needle) !== false) {
$result[$needle] = $haystack;
}
}
var_export($result);
Output:
array (
'needle' => 'needle in haystack text',
'fine' => 'refined',
'' => 'non-empty haystack',
0 => 'This is 0 in a haystack!',
)
From PHP5.6, array_filter()
gained the ARRAY_FILTER_USE_BOTH
flag. This makes array_filter()
an equivalent functional-style technique.
Code: (Demo)
var_export(
array_filter(
$array,
function($haystack, $needle) {
return strpos($haystack, $needle) !== false;
},
ARRAY_FILTER_USE_BOTH
)
);
One advantage of this is that $result
doesn't need to be declared. On the other hand, despite the fact that it can technically be written as a one-liner, it would make a very long line of code -- something that puts the code near or over the soft character limit per line according to PSR-12 coding standards. So there is very little to compel you to change your code so far.
The good news is that PHP8 introduced str_contains()
specifically to offer a clean, native, case-sensitive function to replace strpos()
and its obligatory strict boolean false
check.
Code: (Demo)
var_export(
array_filter($array, 'str_contains', ARRAY_FILTER_USE_BOTH)
);
This returns the same desired output, is a functional-style, one-liner, and concisely spans just 59 characters. I would recommend this approach.
To understand what is happening, the verbose syntax with array_filter()
where str_contains()
is not called by its string name looks like this:
var_export(
array_filter(
$array,
fn($haystack, $needle) => str_contains($haystack, $needle),
ARRAY_FILTER_USE_BOTH
)
);