str_contains, and twenty years of strpos !== false

strpos returns a position, position zero is falsy, and the strict comparison that fixes it is not memorable enough to survive a tidy-up.

// wrong for a needle at the start
if (strpos($haystack, $needle)) { }

// correct, and routinely simplified back to the line above
if (strpos($haystack, $needle) !== false) { }

// 8.0
if (str_contains($haystack, $needle)) { }
if (str_starts_with($path, '/api/')) { }
if (str_ends_with($file, '.php')) { }

This has been the single most common PHP bug for two decades and it is now a language feature rather than a discipline. The three functions are case-sensitive with no flag, which is deliberate — a case-insensitive comparison is a different operation and should look like one. On anything supporting 7.x, symfony/polyfill-php80 provides them and the eventual removal of the polyfill changes nothing else.