Skip to content

RFC for conditional break, continue, & return statements #5552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

ralphschindler
Copy link
Contributor

@ralphschindler ralphschindler commented May 9, 2020

RFC at: https://wiki.php.net/rfc/conditional_break_continue_return

First pass at first class syntactic support for "guard clauses". More technically, a return if.

Example:

function divide($dividend, $divisor = null) {

    return if ($divisor === null);
    
    return if ($divisor == 0): 0;
    
    return $dividend / $divisor;
}

var_dump(divide(10)); // null
var_dump(divide(10, 0)); // 0
var_dump(divide(10, 5)); // 2

https://stackoverflow.com/questions/5436034/is-there-a-ruby-one-line-return-if-x
https://engineering.helpscout.com/reducing-complexity-with-guard-clauses-in-php-and-javascript-74600fd865c7
https://guidelines.spatie.be/code-style/laravel-php#avoid-else (avoid else)

@@ -600,6 +601,17 @@ while_statement:
| ':' inner_statement_list T_ENDWHILE ';' { $$ = $2; }
;

return_if_stmt:
T_RETURN T_IF '(' expr ')' return_if_optional_return
Copy link
Contributor

@carusogabriel carusogabriel May 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this grammar, if without () does not work, e.g.:

<?php

function divide($dividend, $divisor = null): ?int {
    return if $divisor === null; // return null

    return if $divisor === 0 : 0; // explicit return value

    return $dividend / $divisor;
}

Is that expected?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, as currently it is re-using as much syntax that already is known and exists in php. open to discussion though.

@nikic
Copy link
Member

nikic commented May 10, 2020

    return if ($divisor == 0): 0;

This bit of syntax looks very peculiar. Why is this not return 0 if ($divisor == 0);?

@ralphschindler
Copy link
Contributor Author

ralphschindler commented May 10, 2020

I think it is important to communicate the conditionalness of the return early on, as well as what the conditional is, regardless of the length of the response expression.

Since my reasoning requires visuals... :D

edit: also, the: expression for the optional return expression at the end of the full clause has some symmetry with the return type hints in the method signature.

(might have to click to open to see full image)
return-if-visual-reasoning

I will bring to list, more people may have an opinion on order. FWIW, this order was one of my harder decisions up front, I see both ways.

@iluuu1994
Copy link
Member

I think it is important to communicate the conditionalness of the return early on

Then why not just if (condition) return;? It's also the exact same length. I know other languages do this too but I personally never saw the need for it (but that's one opinion).

@ralphschindler
Copy link
Contributor Author

Then why not just if (condition) return;? It's also the exact same length. I know other languages do this too but I personally never saw the need for it (but that's one opinion).

Good points, I think to further clarify my position, this is the priority, order, and intent I wish the statements to communicate:

  1. yes, this line is a return (evident by return being left-most/first on a line)
  2. yes, this return is conditional (evident by the if immediately following the return)
  3. then, the condition itself
  4. optionally, some return value

Even if these statements span multiple lines, this priority and order remains intact to a large degree.

As mentioned in the https://externals.io/message/110107 thread, I am away this is syntactic sugar to some degree, but I feel as proposed, it adds a tremendous amount of value.

@ralphschindler ralphschindler changed the title RFC for return if aka "guard clauses" RFC for conditional break, continue, & return statements May 16, 2020
@zmitic
Copy link

zmitic commented May 18, 2020

Sorry to break in but can this RFC be enhanced with throw? Example:

throw if (!$user = $this->getUser()) : new AccessDeniedException();

If so, it could be expanded with positive if comparison in future:

throw unless ($user = $this->getUser()) : new AccessDeniedException();

One-liners like above would be really nice and readable.

@iluuu1994
Copy link
Member

iluuu1994 commented May 18, 2020

throw unless ($user = $this->getUser()) : new AccessDeniedException();

In PHP 8 you can do this:

$user = $this->getUser() ?? throw new AccessDeniedException();

Which is shorter and way less complex.

int(50)
int(5)
int(0)
string(8) "original"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't forget the newline at the end here :-)

@guss77
Copy link

guss77 commented Jun 28, 2020

Why not just implement full postfix conditions, like in Perl and Ruby? This will allow (almost) the syntax as requested by this RFC but will be a lot more useful:

"fail-fast":

return null if (!$input);

populate values quickly:

$error = "missing home" if (!$home);

Throw errors (like @zmitic) asked:

throw new Exception() if (!$valid);

And if the "guard RFC" will be changed to unless (again, like Perl and Ruby), you'd get even simpler syntax for free:

return null unless($input);

@iluuu1994
Copy link
Member

@ralphschindler Are you planning on pursuing this RFC?

@iluuu1994
Copy link
Member

Closing since there was no response.

@iluuu1994 iluuu1994 closed this Apr 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants