Re: NULL Coercion Consistency
| From: | Craig Francis | Date: | Thu, 05 May 2022 15:29:56 +0000 |
| Subject: | Re: NULL Coercion Consistency | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 12 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-117672@lists.php.net to get a copy of this message | ||
On 3 May 2022, at 14:55, Rowan Tommins <rowan.collins@gmail.com> wrote:
>
> On 03/05/2022 12:37, Craig Francis wrote:
>> But what is that benefit? I'm sorry, but I really don't see it.
>
>
> I started drafting a longer reply, but honestly I don't think we're getting anywhere.
> Every attempt to explain the benefit seems to end in one of two ways:
>
> - an endless back and forth nit-picking hypothetical situations where it might or might not be
> useful
> - an outright dismissal that "people who want it strict can go over there and use
> strict_types=1 and/or static analysis"
>
> To me, it's *always* about trade-offs: the *benefit* of strict checks exists for everyone,
> and the question is whether they want to pay the *cost* or not. As long as we can't agree on
> that fundamental point, there's no point continuing the discussion.
I hope I don't come across like that; I'm really trying to understand the benefits and
costs (I tend to use small examples to help myself understand).
I'm not trying to be dismissive with the use of static analysis. I just think PHP should be
tolerant of some things (e.g. string '5' to int 5, and null to empty string), but I also
recognise some developers prefer a very strict environment that does not do any type coercion
(that's where I think static analysis works really well, as it can enforce extra checks,
including type checks for all variables from all sources to all sinks).
That said, I do see value in some Type Errors, like how I updated my RFC a couple of weeks ago with
some examples "like
substr($string, “offset”) and
htmlspecialchars(array()) as being clearly problematic" (thanks again George).
I'm also fine with substr('abc', $offset) rejecting an Empty String or
NULL for $offset (I'll note that $offset was never added to my list
of 335 parameters).
Under "Future Scope" I've given 4 example parameters that probably should reject an
Empty String or NULL (because they do represent problems, similar to how $separator in
explode() already has the “cannot be empty” fatal error).
And finally, I can see how mt_rand(NULL, NULL) could be a problem (someone assuming
NULL represents a default value, but it's coerced to the integer 0), but as I noted in my
previous email, I cannot find anyone doing this, and after re-checking my lists and having a re-look
though the manual, I think it's the only one that benefits from the rejection of NULL coercion.
Taking that as my rough position on type coercion, I don't see a *benefit* from blocking NULL
coercion (more below).
Whereas, blocking NULL coercion does introduce an upgrade *cost* (not made easier due to the lack of
tooling); and the continuing cost to some developers using the noted frameworks or
filter_input() (e.g. always specifying an empty string default, or always manually
casting NULL to a string)... the other cost is the weirdness in how NULL coercion still works for
echo()/print(), string concatenation, == comparisons, arithmetics, sprintf, etc.
>> I'm going on the basis that you're ok with numbers in strings being coerced to
>> integers/floats (which I also see as being useful, because you're right, most inputs are
>> strings)... but you're not ok with NULL being coerced (which is also common, because values
>> aren't guaranteed to be provided by the user, and NULL is typically the default).
>
>
> I will reply to this point, though, because I think it's a genuinely interesting thing to
> ponder.
>
> One significant difference is that not only is it often not *useful* to distinguish an input of
> 123 from '123', it's often not *possible*. There is literally no way for an HTTP URL
> or header to contain an integer, rather than a string representation of one, because it's not a
> binary protocol.
>
> On the other hand, you might well receive an empty string as input where you're expecting
> an integer. Notably, that is *not* coerced automatically to zero; the code has to explicitly decide
> if that should trigger distinct behaviour (such as a validation error) or be treated as a default
> value. Not receiving a field you expected feels very similar, so similar behaviour feels reasonable.
I'm someone who will try to justify some very strict coding styles - like no inline JavaScript,
use of Trusted Types, the use of literal-string for SQL/HTML/etc, and in some cases the use of
application/xhtml+xml (these have easily provable benefits, but they can also be tricky, so few
developers use them).
With your example, I'm probably fine with an Empty String or NULL not being coerced to int 0
(as in, I could see how it might represent a problem, although I wouldn't care if it did get
coerced to 0).
But a lot of existing PHP code simply takes user input (which can be NULL), and passes it to these
functions with no expectation of a fatal error (not good if it's in mid-way though processing
data).
If we were talking about a desktop application, where the UI was defined and displayed by that
application, then a missing field would represent a problem in that application, but we're
typically talking about the web with PHP, where the data often comes from an un-trusted browser...
i.e. the user/browser/extension/network can be doing something odd, all the way down to how a
standard HTML checkbox works (unchecked does not provide a field).
It's because of these oddities, and the way NULL has historically worked, many developers
simply don't see the difference between an empty or missing field (like other sources of NULL).
That's why I don't see any benefit to blocking NULL coercion in this context, as an Empty
String or NULL are often seen as the same - e.g. a programmer is simply checking if a name was
provided, checking an email address contains the '@' character, checking if a message is
too long, trimming the whitespace from a value, getting a record with an id/slug/name/ref, adding
the value to a url, showing the search term, etc.
Craig