Before PHP 8.1, we could pass null as argument to internal functions even if it does not accept null. On strict_types=1 mode, this triggers TypeError, but on normal/default mode, PHP just silently convert null to the accepted type of that internal function.
var_dump(str_contains("foobar", null)); // bool(true)
str_contains expects both $haystack & $needle to be string, but even if we pass null to it, php accepts it and tries to convert null to string, which is blank string "". As a result function returns true. Even if we passed invalid data to it. /r/lolphp
PHP 8.1 tries to improve this insane behavior
From 8.1, PHP will trigger Deprecation warning whenever we pass null to non-nullable arguments of internal function.
But, it would still accept null and try to convert it to scalar value.
So, running above snippet in 8.1 would return
// Deprecated: str_contains(): Passing null to parameter #2 ($needle) of type string is deprecated bool(true)
It generated deprecated warning and then executed the function anyway.
But Why not just prevent null in non-nullable arguments?
PHP had its internal function system long before it had good type system. At that time, php needed to accept null to cope with its weird weak duck-typing system. And suddenly preventing null will introduce a major backward compatibility break.
So, devs decided to throw deprecation warning for now and remove this insanity on PHP 9.0
Note: This behavior is not allowed on strict type mode. Strict mode prevent lots of other type conversion insanity in PHP, so please consider enabling strict type mode whenever you write new codes.
declare(strict_types=1); // we've enabled strict type mode var_dump(str_contains("foobar", null)); //Uncaught TypeError: str_contains(): Argument #2 ($needle) must be of type string, null given
Be safe now, or be sorry later.