On Fri, 3 Jan 2025 at 16:03, Kamil Tekiela <tekiela...@gmail.com> wrote:

> It is a step towards making the user-defined functions and built-in
> functions consistent with each other.
>


Just to note, it could have been "consistent" if NULL coercion was
supported for user-defined functions (when not using strict types), in the
same way that user defined functions coerce the other types:


function example(string $s, int $i) {
  var_dump($s);
  var_dump($i);
}

example("123", "321");
example(123, 321);
example(1.23, 3.21); // Deprecated, 3.21 loses precision to 3 (which is
fair)
example(true, false);
example(NULL, NULL); // Will be a fatal error in PHP 9?


Fortunately NULL coercion does still work in other contexts:

$nullable = NULL;
if ('' == $nullable) {}
print($nullable);
echo $nullable;
sprintf('%s', $nullable);
var_dump('ConCat ' . $nullable);
var_dump(3 + '5' + $nullable);
var_dump($nullable / 6);


And, NULL coercion is documented:

https://www.php.net/manual/en/language.types.string.php

“null is always converted to an empty string”

https://www.php.net/manual/en/language.types.integer.php

“null is always converted to zero (0)”

https://www.php.net/manual/en/language.types.float.php

“For values of other types, the conversion is performed by converting the
value to int first and then to float”

https://www.php.net/manual/en/language.types.boolean.php

“When converting to bool, the following values are considered false [...]
the unit type NULL”


---


> You say that $fieldValue in your code can be either a string or null, but
> you don't explain why it can be null.



When working with web pages (think GET/POST/COOKIE values), or databases,
NULL is common:


$search = ($_GET['q'] ?? NULL); // Common since PHP 7

$search = (isset($_GET['q']) ? $_GET['q'] : NULL);

$search = filter_input(INPUT_GET, 'q');

$search = $request->input('q'); // Laravel
$search = $request->get('q'); // Symfony
$search = $this->request->getQuery('q'); // CakePHP
$search = $request->getGet('q'); // CodeIgniter


---


> Using ?? '’ is a cheap solution to avoid the deprecation message, but it's
> not a good solution.



An alternative is to use `(string) $var`, which some may argue is more
dangerous than using coercion :-)

This is how Rector deals with the issue;
the NullToStrictStringFuncCallArgRector will litter your code with loads of
changes, basically anything it can't be sure of the type will be coerced:

-echo htmlspecialchars($var)
+echo htmlspecialchars((string) $var)

And it needs to do this for ~287 functions:

https://github.com/rectorphp/rector-src/blob/main/rules/Php81/Enum/NameNullToStrictNullFunctionMap.php

There are several projects I have not done this to (because it changes
thousands of lines of code).

With new code, I've just go into the habit of doing ugly things like
`trim(strval($a))`, and for templating I've taken a similar approach
to Laravel Blade (abstracting the use of htmlspecialchars):

https://github.com/laravel/framework/blob/ab1506091b9f166b312b3990d07b2e21d971f2e6/src/Illuminate/Support/helpers.php#L119

That said, as I expect PHP 9 to trigger a Fatal Error every time this
happens (last time I raised this, lets just say it wasn't a pleasant
experience), I'm tempted to create a simple library to re-define all of
these functions, e.g.


namespace FixNullCoercion;

function urlencode($string) {
  return \urlencode($string ?? '');
}

function trim($string, $characters = " \n\r\t\v\x00") {
  return \trim($string ?? '', $characters);
}

function htmlspecialchars($string, $flags = ENT_QUOTES | ENT_SUBSTITUTE |
ENT_HTML401, $encoding = null, $double_encode = true) {
  return \htmlspecialchars($string ?? '', $flags, $encoding,
$double_encode);
}

// ... etc for the ~287 functions.


Then anyone can include the library, and simply use
the FixNullCoercion namespace.

In the mean time, as a quick and simple way to ignore the deprecation
message, I'm using:


function ignore_null_coercion($errno, $errstr) {
  return ($errno === E_DEPRECATED && preg_match('/Passing null to parameter
#.* of type .* is deprecated/', $errstr));
}
set_error_handler('ignore_null_coercion', E_DEPRECATED);


Craig

Reply via email to