katedev9 Nov 2025 19:42

PHP 8 added str_contains, str_starts_with, str_ends_with. These replace the strpos pattern. Is there more to it than readability?

Replies (5)
alex_petrov9 Nov 2025 19:51

The main fix is the strpos === false pattern which was error-prone. strpos returns 0 when the needle is at position 0, which is falsy in a loose comparison. Classic bug:

PHP
<?php
$url = 'https://example.com/path';
$needle = 'https';
// BUG: this is always false because strpos returns 0 (truthy check fails)
if (strpos($url, $needle)) {
echo "found (wrong)\n";
} else {
echo "not found (wrong)\n";
}
// CORRECT old way
if (strpos($url, $needle) !== false) {
echo "found (correct old)\n";
}
// CORRECT new way
if (str_starts_with($url, $needle)) {
echo "found (str_starts_with)\n";
}
// str_contains for middle occurrence
$haystack = 'Hello World';
var_dump(str_contains($haystack, 'World')); // bool(true)
var_dump(str_contains($haystack, '')); // bool(true) - empty needle always true
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0
nphp9 Nov 2025 20:16

Performance is identical for most inputs. They both use Boyer-Moore-Horspool internally for longer strings. No reason to prefer strpos for performance.

0
sergey_web9 Nov 2025 21:45

str_starts_with and str_ends_with are the bigger wins. The old substr($str, 0, strlen($prefix)) === $prefix pattern was verbose and error-prone for unicode strings.

0
vova9 Nov 2025 22:27

One gotcha: str_contains(“”, “”) returns true. An empty needle is found at position 0 in any string including an empty string. strpos(“”, “”) returns 0 and is truthy. Same behavior, be aware.

0
ivan_morozov9 Nov 2025 23:01

Rector and PHP-CS-Fixer can automate the strpos to str_contains migration. Not worth doing manually but a one-time automated pass is easy.

0
Write a reply
Markdown. ```php blocks are runnable.