Re: [RFC] Deprecate type juggling to and from bool type within the function type juggling context
| From: | Rob Landers | Date: | Sat, 12 Jul 2025 20:29:26 +0000 |
| Subject: | Re: [RFC] Deprecate type juggling to and from bool type within the function type juggling context | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-128017@lists.php.net to get a copy of this message | ||
On Sat, Jul 12, 2025, at 01:29, Theodore Brown wrote:
> On Fri, July 11, 2025 at 05:00 G. P. Banyard wrote:
>
> >> On Monday, 30 June 2025 at 10:26, Nicolas Grekas wrote:
> >> ...
> >> The latter, cast-from-bool, I think they're all useful improvements.. While most
> >> likely harmless in all the specific
> >> cases of the PR, doing e.g. an strpos() on false feels hardly legit.. I'm
> >> therefore sympathetic to making these changes.
> >>
> >> For cast-to-bool, I'm WAY less convinced. From the PR above, explicit casts like
> >> "return (bool) preg_match(...)"
> >> on a method that returns a "bool" or "(bool) ($this->loggedErrors
> >> & $type)" are a clear downgrade: it makes the
> >> typing PHP just more verbose without any real benefit. That doesn't look worth
> >> asking the whole ecosystem to fix
> >> those deprecations. It is especially hard to see this as an improvement when comparing
> >> to using the same
> >> expressions with e.g. the "if ()" operator, which doesn't need the
> >> explicit cast (and shouldn't of course).
>
> From my experience there is a very real benefit to deprecating both cast-from-bool and
> cast-to-bool.
> Let me give an example of both.
>
> Recently had to fix some legacy code where the result of
>
filemtime was being passed to gmdate
> to format
> the modification timestamp. filemtime returns false on failure,
> but this is silently coerced to zero
> (a valid timestamp) when passed to the int parameter, which would result in the script
> continuing with bad
> data instead of halting with a type error.
>
> Cast-to-bool can cause the same kinds of issues, which are sometimes even harder to notice.
> Consider the following:
>
> function processArray(array $items, bool $hasCertainKey) { ... }
>
> $keyOrFalse = array_search('my value', $items);
>
> processArray($items, $keyOrFalse);
>
> It's very easy to miss the bug in this code, especially since it seems to function
> correctly as long as 'my value'
> is not in the array, or is not the first item in the array. However, when it's at index 0
> the key will be silently
> coerced to false and the array will be incorrectly processed as though the value is not in the
> array.
>
> I believe deprecating type juggling to/from bool will help avoid creating bugs like this (and
> likely
> surface existing ones that should be fixed).
>
> Kind regards,
> Theodore
I'm not so confident that will be the case. In lots of strict-mode code I've worked with
over the years, people tend to blindly cast things without realizing they're in a worse
situation than using non-strict mode. Like ((int)"123password") === 123,
however attempting to coerce that string to an int results in a proper type error in non-strict
mode.
That is to say, I highly suspect that gmdate(filemtime($file)) would just be rewritten
as gmdate((int)filemtime($file)) without a second thought.
In your other example showing the difference in array_search, I also highly suspect people would
just cast it to bool without noticing the 0-key edge case.
Both cases, I believe, can simply be solved by tooling highlighting when you're passing a union
type to a function that doesn't overlap with the function's expectations. ("you are
passing int|string to a function expecting bool" and/or "you are casting int|string to
bool, check that (bool)"0" won't be an edge-case; consider using empty()
instead").
— Rob