Hello,
We remember the old days, when we had to do:
function getUnreadDocuments(): int {
$user = Auth::user();
if (is_null($user)) return 0;
$documents = $user->getDocuments();
if (is_null($documents)) return 0;
// actual logic of the function
return 42;
}
And it was already really nice to do:
function getUnreadDocuments(): int {
$documents = Auth::user()?->getDocuments();
if (is_null($documents)) return;
// actual logic of the function
return 42;
}
But I think it could be written even more concise with just reusing
existing syntax elements:
function getUnreadDocuments(): int {
$documents = Auth::user()?->getDocuments() ?? return 0;
// actual logic of the function
return 42;
}
This is exactly the type of change that PHP 8.0 introduced for throw (
https://wiki.php.net/rfc/throw_expression) and to me it feels very natural
to write code that has this change also made for the return statement. In
the example above, depending on developer preference, the same result could
be achieved with " || return 0;" instead of the ?? operator.
Was there any previous discussion about this and was there maybe a good
reason it hasn't been implemented? I couldn't find anything when searching.
What are your thoughts on this?
-Florian
function getUnreadDocuments(): int {
$documents = Auth::user()?->getDocuments() ?? return 0;
// actual logic of the function
return 42;
}
I think I'd probably reject that example as too cryptic in a code
review; the mixture of assignment and control flow is hard to follow,
even more so than this, which is already possible:
if ( ! $documents = Auth::user()?->getDocuments() ) return 0;
I can imagine some people would like it, though, particularly those used
to the Perl "doSomething() or die;" idiom.
The throw expression has uses in things like lambdas and match
expressions, which only accept expressions not statements. I can't think
of any examples where "return" would be useful in such contexts, and in
fact wonder what they'd even do:
return $foo = match(1) { default => return 42; }
$foo = fn() => return 42;
function foo() { return return 42; } // presumably you could stack this
endlessly, "return return return return 42;"
function foo() { yield return 42; }
Throwing exceptions already aborts the control flow, so doing so in the
middle of an expression is easy to understand; having an early return in
the middle of an expression is harder to understand.
Regards,
--
Rowan Tommins
[IMSoP]