Convert return to expression like throw

php.internals

Florian Stascheck

4 years ago
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

Rowan Collins

4 years ago
On 18/03/2022 10:18, Florian Stascheck wrote:
> 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]