On 8 April 2022 18:34:52 BST, Craig Francis <cr...@craigfrancis.co.uk> wrote:
>I've written a new draft RFC to address the NULL coercion problems:

I'm sympathetic to the general problem you're trying to solve, but I'm not 
convinced by the argument that this is about consistency, because user defined 
functions have been consistently rejecting null for non-nullable parameters 
since PHP 7.0, and even before that for arrays and objects. Consistency is a 
good argument for small changes that eliminate unusual edge cases, but I think 
far-reaching changes should be able to stand on their own merits - regardless 
of whether it's consistent, do we want the language to work this way?

To me, the main defence of type coercion is that PHP operates in a world full 
of strings - URLs are strings, HTTP requests are strings, and a lot of API 
responses are strings - so making it easy to work with strings like '42' as 
numbers makes a lot of sense. It's not clear to me that this extends to null.

I think a large part of the problem here is that null can mean many different 
things in different contexts - "unknown", "not provided", "invalid input", 
"default", "not applicable", etc.

These differences are subtle, but lead to different expectations of behaviour:

- Treat null as a specific case with its own meaning, distinct from any other 
valid value. This is what explicitly nullable parameters and union types allow.
- Treat null the same as any other out of range value, and raise an error. This 
is what happens in user-defined functions in PHP, and in built-in functions 
expecting non-scalar arguments. Compare also out of range actions like division 
by zero.
- Treat null as a special state that propagates through expressions, because 
any operation with an unknown input has an unknown output. This is the approach 
to null taken by SQL, and by IEEE floating point with NaN. It is also the basis 
of the ?-> operator, and of things like Optional.map in Swift.
- Treat null as a generic default value which can be filled in implicitly based 
on requirements. This is the interpretation currently taken by internal 
functions for scalar arguments, and what you are proposing to make standard. It 
is also, as you point out, the way PHP treats null in some other contexts, such 
as many operators.

Interestingly, one of your examples mentions filter_input, which takes the 
"propagate" approach, and htmlspecialchars, which doesn't. It would often be 
more useful to retain the information that a value is null than to have it 
silently converted to an empty string as a side-effect of some other operation. 

Perhaps it would be useful to have some function-call equivalent of the ?-> 
operator. I'm not sure what this would look like for normal function calls, but 
it would be easy to add if we had a pipe operator, e.g.:

If this was equivalent to htmlspecialchars($foo)
$foo |> htmlspecialchars(...)

Then this could be equivalent to ($foo === null ? null : htmlspecialchars($foo))
$foo ?|> htmlspecialchars(...)

I'm not set against this RFC, but I'm not quite convinced by the case it makes, 
and think there may still be other options to explore.


Rowan Tommins

PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to