Hi everybody! I hope you’re doing well.
Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
https://wiki.php.net/rfc/throw_expression
In short, the RFC proposes to convert the throw statement into an expression to make it usable in arrow functions, the coalesce operator, as well as the ternary/elvis operator.
If you have any feedback, concerns, or if you want to express your interest or lack thereof, let me know!
Regards
Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
Regarding the example:
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');
The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.
Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?
cheers
Dan
Ack
Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
Regarding the example:
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?
Why can't you just do this in userland code?
function throwException(Exception $exception) {
throw $exception;
}
$callable = fn() => throwException( new Exception() );
// $value is non-nullable.
$value = $nullableValue ?? throwException( new InvalidArgumentException() );
// $value is truthy.
$value = $falsableValue ?: throwException( new InvalidArgumentException() );
// $value is only set if the array is not empty.
$value = !empty($array)
? reset($array)
: throwException( new InvalidArgumentException() );
-Mike
P.S. I am probably in the vast minority on this list but I would like to see fewer places that throw exceptions, not more.
I want to deal with errors where they happen, not throw exceptions or have to catch them as I have found that I can write much more robust and easier to read code when I write without using exceptions. I came to this realization because of learning that Go does not endorse exceptions and then I learned why they do not which strongly resonated with me. After that, I finally felt comfortable saying that "Exceptions seemed like a good idea at the time."
I now have a whole slew of classes who only purpose is to wrap PHP functions and classes that throw exceptions so I can call them w/o having to use try{}catch{}. Instead I use an if() afterwards to check and then handle it if there was an error.
One particularizing problematic exception in PHP is with the DataTime class. I have found it effectively impossible to create a class that extends DateTime without having the potential for an exception to be thrown (unless someone knows a way that I do not?) The potential is actually hypothetical, but PhpStorm nonetheless still complains that I have not handled exceptions when using that child class.
Hi Mike
Thanks for your feedback!
Your solution works well and it's true that PHP would do just fine without accepting this RFC.
However I do think this RFC makes sense for a few reasons:
- I think that most people would expect some of the examples (especially the arrow function) to be valid PHP code
- Adding a throwException function will unnecessarily fragment your codebase into throw statements and calls to that function
- It's not as static analysis friendly
- The patch has very low complexity
I agree that some languages do well with returning errors instead of throwing them. I personally don't think it's a good fit for PHP because PHP can't enforce you to handle these cases.
Regards
On 22.03.20, 19:14, "Mike Schinkel" mike@newclarity.net wrote:
>
>
>
>>
>> Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
>>
>> https://wiki.php.net/rfc/throw_expression
>>
>
> Regarding the example:
>
> $condition || throw new Exception('$condition must be truthy')
> && $condition2 || throw new Exception('$condition2 must be truthy');
>
> The "Deprecate left-associative ternary operator"* RFC made it so that
> parentheses are required when ternary operators are nested in
> complicated statements.
>
> Would a similar requirement for parentheses around complicated throw
> expressions be a suitable solution to avoid people being surprised by
> the behaviour?
>
Why can't you just do this in userland code?
function throwException(Exception $exception) {
throw $exception;
}
$callable = fn() => throwException( new Exception() );
// $value is non-nullable.
$value = $nullableValue ?? throwException( new InvalidArgumentException() );
// $value is truthy.
$value = $falsableValue ?: throwException( new InvalidArgumentException() );
// $value is only set if the array is not empty.
$value = !empty($array)
? reset($array)
: throwException( new InvalidArgumentException() );
-Mike
P.S. I am probably in the vast minority on this list but I would like to see fewer places that throw exceptions, not more.
I want to deal with errors where they happen, not throw exceptions or have to catch them as I have found that I can write much more robust and easier to read code when I write without using exceptions. I came to this realization because of learning that Go does not endorse exceptions and then I learned why they do not which strongly resonated with me. After that, I finally felt comfortable saying that "Exceptions seemed like a good idea at the time."
I now have a whole slew of classes who only purpose is to wrap PHP functions and classes that throw exceptions so I can call them w/o having to use try{}catch{}. Instead I use an if() afterwards to check and then handle it if there was an error.
One particularizing problematic exception in PHP is with the DataTime class. I have found it effectively impossible to create a class that extends DateTime without having the potential for an exception to be thrown (unless someone knows a way that I do not?) The potential is actually hypothetical, but PhpStorm nonetheless still complains that I have not handled exceptions when using that child class.
Hi Mike
Thanks for your feedback!
Your solution works well and it's true that PHP would do just fine without accepting this RFC.
However I do think this RFC makes sense for a few reasons:
- I think that most people would expect some of the examples (especially the arrow function) to be valid PHP code
- Adding a throwException function will unnecessarily fragment your codebase into throw statements and calls to that function
- It's not as static analysis friendly
- The patch has very low complexity
I agree that some languages do well with returning errors instead of throwing them. I personally don't think it's a good fit for PHP because PHP can't enforce you to handle these cases.
Regards
Hi Ilija,
I am fine if other people use exceptions as long as I have ways to not have to use them.
The lack of enforcement is not a concern for me, that is what code review is for. However if error handling vs exception handling were elevated to a standardized alternate strategy by PHP then static analysis could catch lack of handling said errors.
In the case of allowing people to throw exceptions in expressions that just means for me that I have more code I have to wrap to avoid having to deal with those exceptions throughout my code if and when I use other people's code from Packagist or GitHub.
-Mike
P.S. However, I think my opinion on exceptions in PHP is in the minority, mine is only one opinion, and I don't even have a vote so I am not sure it matters what my preference is on this topic.
On 22.03.20, 19:14, "Mike Schinkel" mike@newclarity.net wrote:
Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
Regarding the example:
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?Why can't you just do this in userland code?
function throwException(Exception $exception) {
throw $exception;
}$callable = fn() => throwException( new Exception() );
// $value is non-nullable.
$value = $nullableValue ?? throwException( new InvalidArgumentException() );// $value is truthy.
$value = $falsableValue ?: throwException( new InvalidArgumentException() );// $value is only set if the array is not empty.
$value = !empty($array)
? reset($array)
: throwException( new InvalidArgumentException() );-Mike
P.S. I am probably in the vast minority on this list but I would like to see fewer places that throw exceptions, not more.I want to deal with errors where they happen, not throw exceptions or have to catch them as I have found that I can write much more robust and easier to read code when I write without using exceptions. I came to this realization because of learning that Go does not endorse exceptions and then I learned why they do not which strongly resonated with me. After that, I finally felt comfortable saying that "Exceptions seemed like a good idea at the time."
I now have a whole slew of classes who only purpose is to wrap PHP functions and classes that throw exceptions so I can call them w/o having to use try{}catch{}. Instead I use an if() afterwards to check and then handle it if there was an error.
One particularizing problematic exception in PHP is with the DataTime class. I have found it effectively impossible to create a class that extends DateTime without having the potential for an exception to be thrown (unless someone knows a way that I do not?) The potential is actually hypothetical, but PhpStorm nonetheless still complains that I have not handled exceptions when using that child class.
Hi Dan
Interesting suggestion. I'll have to think more about how many of these variations there are and if there's an easy way to recognize them.
Ilija
On 22.03.20, 18:16, "Dan Ackroyd" Danack@basereality.com wrote:
>
> Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
>
> https://wiki.php.net/rfc/throw_expression
>
Regarding the example:
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');
The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.
Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?
cheers
Dan
Ack
* https://wiki.php.net/rfc/ternary_associativity
Hi Dan,
Dan Ackroyd wrote:
Regarding the example:
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?cheers
Dan
Ack
Is there a strong reason to require parentheses? I would think we can
just give throw
an appropriate precedence so that expressions like the
above do what is desired — and then if you wanted to do something
unusual, you would have to add parentheses anyway.
Regards,
Andrea
$condition || throw new Exception('$condition must be truthy')
&& $condition2 || throw new Exception('$condition2 must be truthy');The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.Would a similar requirement for parentheses around complicated throw
expressions be a suitable solution to avoid people being surprised by
the behaviour?
I've thought about this some more. There is a reasonable way to recognize this, namely to check if the expression after the throw keyword is of type ZEND_AST_OR or ZEND_AST_AND. The expression above will fail with this message (given that $condition is false):
Fatal error: Uncaught Error: Can only throw objects in ...
IMO this is clear enough that a message for this edge case is not necessary.
I think this is great.
It reminds me of a construct that Hack introduced called "as expressions":
With throw expressions the Hack assignment,
$a = $b as string;
would be equivalent to the PHP assignment
$a = is_string($b) ? $b : throw new TypeError('$b must be a string');
If this passes, it would be great to see sugary equivalents get added to
the language too.
Hi everybody! I hope you’re doing well.
Due to the modest feedback I’d like to move the throw expression RFC to
“under discussion”.https://wiki.php.net/rfc/throw_expression
In short, the RFC proposes to convert the throw statement into an
expression to make it usable in arrow functions, the coalesce operator, as
well as the ternary/elvis operator.If you have any feedback, concerns, or if you want to express your
interest or lack thereof, let me know!Regards
Hey Ilija,
Ilija Tovilo wrote:
Hi everybody! I hope you’re doing well.
Due to the modest feedback I’d like to move the throw expression RFC to “under discussion”.
https://wiki.php.net/rfc/throw_expression
In short, the RFC proposes to convert the throw statement into an expression to make it usable in arrow functions, the coalesce operator, as well as the ternary/elvis operator.
Thanks for this RFC, I have wanted this sometimes when writing PHP code.
The ?? operator is one of those places, but I am surprised you haven't
mentioned the and
and or
operators.
It is classic PHP style (probably borrowed from Perl?) to write e.g.:
$mysql = mysql_open(...) or die("Couldn't connect to MySQL");
Obviously not very modern with use of mysql_ ;)
But the or
operator is still quite handy for this kind of trivial
error handling, and it would be great to be able to write e.g.:
$fp = @fopen($filename, "r") or throw new Exception("Couldn't open
file!");
Likewise for and
(I think it is less common):
$somethingWentWrong and throw new Exception("Oh no!");
So I would be happy to see throw
become an expression for these
reasons, even if it is a bit conceptually weird given it never returns
anything!
Thanks,
Andrea
Hi everybody! I hope you’re doing well.
Due to the modest feedback I’d like to move the throw expression RFC to
“under discussion”.https://wiki.php.net/rfc/throw_expression
In short, the RFC proposes to convert the throw statement into an
expression to make it usable in arrow functions, the coalesce operator, as
well as the ternary/elvis operator.If you have any feedback, concerns, or if you want to express your
interest or lack thereof, let me know!
Looks like a reasonable change to me. Maybe interesting to compare with the
ECMAScript and C# proposals you reference:
The ECMAScript proposal (https://tc39.es/proposal-throw-expressions/)
defines the throw expression as a very high precedence operator, rather
than a low precedence one. There's discussion on that in
https://github.com/tc39/proposal-throw-expressions/issues/10. Reading that
thread, it seems like nobody actually wants the high precedence version,
but there are some ECMAScript-specific issues with low precedence, because
of conflicts with comma expressions. Thankfully that doesn't apply to us.
The C# proposal (
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.0/throw-expression)
limits the use of throw expressions to specific context only (in short
lambdas and on the right hand side of ?: and ??). I'm personally not a fan
of that, unless there's a technical motivation for that. If it's just about
enforcing coding style, there's already plenty of weird expressions you can
write right now. I don't want to add special cases to the language
specification to enforce someone's style preferences.
The "Deprecate left-associative ternary operator"* RFC made it so that
parentheses are required when ternary operators are nested in
complicated statements.
I should probably explicitly say here that the parentheses are required not
because I think it is a good idea to require them, but to avoid changing
the interpretation of an expression from one version to the next. Given
that we did end up changing the precedence of the "." operator (rather than
requiring parentheses), this choice is somewhat dubious now, and it would
have been better to simply change the interpretation of the ternary in PHP
8 as well.
Regards,
Nikita