Re: Proposal: AS assertions
| From: | Rowan Tommins [IMSoP] | Date: | Fri, 22 Mar 2024 15:18:46 +0000 |
| Subject: | Re: Proposal: AS assertions | ||
| References: | 1 2 3 4 5 6 7 8 9 10 11 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122728@lists.php.net to get a copy of this message | ||
On Fri, 22 Mar 2024, at 12:58, Robert Landers wrote:
>
>> $optionalExpiryDateTime = $expiry as ?DateTimeInterface else new
>> DateTimeImmutable($expiry);
> I'm not sure I can grok what this does...
>
> $optionalExpiryDateTime = ($expiry === null || $expiry instanceof
> DateTimeInterface) ? $expiry : new DateTimeImmutable($expiry)
Trying to write it as a one-liner is going to make for ugly code - that's why I'd love to
have a new way to write it! But yes, that's the right logic.
With the "is" operator from the Pattern Matching draft, it would be:
$optionalExpiryDateTime = ($expiry is ?DateTimeInterface) ? $expiry : new
DateTimeImmutable($expiry);
But with a clearer assertion that the variable will end up with the right type in all cases:
$optionalExpiryDateTime = $expiry as ?DateTimeInterface else some_other_function($expiry);
assert($optionalExpiryDateTime is ?DateTimeInterface); // cannot fail, already asserted by the
"as"
> Maybe? What would be the usefulness of this in real life code? I've
> never written anything like it in my life.
I already explained the scenario: the parameter is optional, so you want to preserve nulls; but if
it *is* present, you want to make sure it's the correct type before proceeding. Another
example:
// some library function that only supports strings and nulls
function bar(?string $name) {
if ( $string !== null ) ...
else ...
}
// a function you're writing that supports various alternative formats
function foo(string|Stringable|int|null $name = null) {
// we don't want to do anything special with nulls here, just pass them along
// but we do want to convert other types to string, so that bar() doesn't reject them
bar($name as ?string else (string)$name);
}
To put it another way, it's no different from any other union type: at some point, you will
probably want to handle the different types separately, but at this point in the program, either
type is fine. In this case, the types that are fine are DateTimeInterface and null; or in the
example above, string and null.
> $optionalExpiryDateTime = $expiry == null ? $expiry : $expiry as
> DateTimeInterface ?? new DateTimeImmutable($expiry as string ?? "now")
If you think that's "readable" then we might as well end the conversation here. If
that was presented to me in a code review, I'd probably just write "WTF?!"
I have no idea looking at that what type I can assume for $optionalExpiryDateTime after that line,
which was surely the whole point of using "as" in the first place?
Regards,
--
Rowan Tommins
[IMSoP]