PHP 8.0: New str_contains
function
One of the usability improvements that comes with PHP 8.0 is the new str_contains
function. As the name suggests, it checks if the given haystack string contains a given string needle.
Without this function, the usual way to find if a given string contains another string is to use to the strpos()
function:
if (strpos('Foo Bar Baz', 'Bar') !== false) {
echo 'Found';
}
strpos()
function returns the position of the needle string, or false
if the needle is not found. This is error-prone, because if the needle is found at the position 0
of the haystack, it evaluates to false
unless strict comparison (===
) used.
To explain further, the following snippet is not correct:
if (strpos('Foo Bar Baz', 'Foo')) {
echo 'Found';
}
Because Foo
is found at the beginning of the haystack, the return value of strpos()
call will be 0
, which evaluates to false, and the if
block will not run.
With the new str_contains
function, it is easy to do this:
if (str_contains('Foo Bar Baz', 'Foo')) {
echo 'Found';
}
Case sensitivity
str_contains()
function is case-sensitive. There is no case-insensitive variant of this function. There is no technical reason to not have a case-insensitive str_icontains()
function, but there isn't one for now to keep things simple.
Multi-byte strings
For strpos()
function, there is a multi-byte safe mb_strpos()
variant. However, for str_contains()
function, there is no mb_str_contains()
function. This is because internally, PHP strings are streams of bytes, and an mb_str_contains()
function will be identical to the functionality of str_contains()
as it would be checking for a sequence of bytes in another sequence of bytes anyway.
Conflicts with user-land implementations
There are several user-land implementations of this functionality, often with the exact same name. As of this moment, there are over 192K str_contains()
matches on Github, and over 6K search results of str_contains()
function declarations.
Most notably, Laravel offers a helper function str_contains()
, but this function accepts an array of needles for the second parameter as well, which is not compatible with PHP core implementation.
Empty strings
If you search for an empty needle (""
), PHP will always return true
. To quote Nikita:
As of PHP 8, behavior of '' in string search functions is well defined, and we consider '' to occur at every position in the string, including one past the end. As such, both of these will (or at least should) return true. The empty string is contained in every string.
This means the following will always returns true
:
str_contains('Foo', ''); // true
str_contains('', ''); // true
Polyfills
A PHP 7.0+ compatible polyfill is straight forward and simple:
if (!function_exists('str_contains')) {
function str_contains(string $haystack, string $needle): bool {
return '' === $needle || false !== strpos($haystack, $needle);
}
}
Backwards compatibility impact
str_contains()
is a new function; Unless you already have a str_contains()
function declared, there should be no BC impact.
Most user-land implementations only declare its own str_contains()
function only if that function does not exists. You might run into obscure bugs if the user-land implementations are incompatible with PHP core's. See the section above about user-land implementations.