str_contains vs strpos: what actually changed and what to use
PHP 8 added str_contains, str_starts_with, str_ends_with. These replace the strpos pattern. Is there more to it than readability?
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:
Performance is identical for most inputs. They both use Boyer-Moore-Horspool internally for longer strings. No reason to prefer strpos for performance.
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.
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.
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.
```php blocks are runnable.