[RFC] Extend error control operator to suppress exceptions

php.internals

Girgias

5 years ago
Hello internals, This new RFC which I'm proposing is to extend the capability of the error control operator @ to not just suppress diagnostic messages but also exceptions. It can currently be found on GitHub: [1] https://github.com/Girgias/error-control-operator-exceptions-rfc The main motivation for this is to provide a path to migrate in a backwards compatible manner away from diagnostics such as E_WARNING to the use of exceptions without breaking 99% of PHP code which has been written in the last 25years. This proposal on it's own would not be sufficient to trigger such a change for extensions but in combination with another proposal to introduce a `throw_on_error` declare [2] it could provide a bridge for a gradual transition to the use of more exceptions internally. Although I'm not thrilled with the idea of shoving more functionality into @ I don't see any other way, and thus I think it a necessary evil to improve the long term health of the PHP project. Feedback on this RFC and different ideas on how to tackle this topic are highly appreciated and welcomed. Best regards, George P. Banyard [1] https://github.com/Girgias/error-control-operator-exceptions-rfc [2] Draft RFC for throw_on_error declare https://github.com/Girgias/php-rfc-throw-on-error-declare

AllenJB

5 years ago
On 04/03/2021 14:08, G. P. B. wrote:
> Hello internals, > > This new RFC which I'm proposing is to extend the capability of the error > control operator @ to not just suppress diagnostic messages but also > exceptions. > It can currently be found on GitHub: [1] > https://github.com/Girgias/error-control-operator-exceptions-rfc > > The main motivation for this is to provide a path to migrate in a backwards > compatible manner away from diagnostics such as E_WARNING to the use of > exceptions without breaking 99% of PHP code which has been written in the > last 25years. > > This proposal on it's own would not be sufficient to trigger such a change > for extensions but in combination with another proposal to introduce a > `throw_on_error` declare [2] it could provide a bridge for a gradual > transition to the use of more exceptions internally. > > Although I'm not thrilled with the idea of shoving more functionality into > @ I don't see any other way, and thus I think it a necessary evil to > improve the long term health of the PHP project. > > Feedback on this RFC and different ideas on how to tackle this topic are > highly appreciated and welcomed. > > Best regards, > > George P. Banyard > > [1] https://github.com/Girgias/error-control-operator-exceptions-rfc > [2] Draft RFC for throw_on_error declare > https://github.com/Girgias/php-rfc-throw-on-error-declare
> as the I/O API has been revamped within the SPL extension but the
usage of the traditional I/O functions remains the de facto standard within the community. I don't think that this is really an argument for anything. The SPL options aren't obvious - I would wager that many, most even, PHP developers barely even know SPL exists. The SPL options aren't pushed anywhere in the manual that I'm aware of (for example, the manual page for dir() doesn't even mention FilesystemIterator / DirecrtoryIterator in any way). Many developers are already using Safe and similar libraries to get "standard library but with exceptions". If this was available in core and at least prominently mentioned, if not recommended in the manual (could we have a "note box" that's not quite a deprecation notice, but a "we strongly urge you to consider this method" in a similar fashion, if we don't already?) If the manual did a similarly better job of recommending SPL ways of doing things, I'm sure they'd get used more too. Would it make sense in some areas such as file operations to have more "topic oriented" documentation than the current pure function / class listing methodology the manual currently uses? (This might make it easier to point out alternatives or make recommendations) On a related note I dislike "documentation burden" as an argument against improvements. I obviously understand "open source, volunteers, translations, etc" but I've heard this a few times now as an argument against fixing various issues (another example is that many functions in the manual document that they can return false, but there's absolutely no explanation as to when this can occur except a single paragraph that lives on its own page that nobody is ever likely to find if they don't already know it exists and you can't tell which functions it actually applies to even if you do). Obviously the project doesn't, but if you followed this for everything (to the extreme), you'd never introduce any new functionality because it would mean adding more documentation pages. If this is an issue, does the project need to consider if there are better ways to handle documentation? Are there things the project could implement to improve documentation contributions and recruit more translators (something along the lines of "bug days" or "Season of Docs"; this might be easier to implement now that the docs are in Git(Hub)) With regards to the suggested implementations, I would prefer the improved library with exceptions option. I wouldn't like to see yet another method of error handling introduced to the standard library (such as the Go 2 returns method) - it already has too many. Things have been moving in a good direction recently with everything moving toward Throwables. I think reversing that trend is a mistake. Potentially crazy thought: Running with the "improved standard library" idea, could this be made easier for developers to use by implementing a "use fallback namespace" statement. While PHP currently falls back to root / namespace, if the new standard library were - purely for example, I'm sure others can come up with a better name - under the namespace "/PHP/standard/", developers could add "use fallback namespace /PHP/standard/;" to the top of their scripts along with the other use statements, and PHP would then try that namespace before falling back further to / when encountering undefined classes.

Girgias

5 years ago
On Thu, 4 Mar 2021 at 16:06, AllenJB <php.lists@allenjb.me.uk> wrote:
> > On 04/03/2021 14:08, G. P. B. wrote: > > Hello internals, > > > > This new RFC which I'm proposing is to extend the capability of the error > > control operator @ to not just suppress diagnostic messages but also > > exceptions. > > It can currently be found on GitHub: [1] > > https://github.com/Girgias/error-control-operator-exceptions-rfc > > > > The main motivation for this is to provide a path to migrate in a > backwards > > compatible manner away from diagnostics such as E_WARNING to the use of > > exceptions without breaking 99% of PHP code which has been written in the > > last 25years. > > > > This proposal on it's own would not be sufficient to trigger such a > change > > for extensions but in combination with another proposal to introduce a > > `throw_on_error` declare [2] it could provide a bridge for a gradual > > transition to the use of more exceptions internally. > > > > Although I'm not thrilled with the idea of shoving more functionality > into > > @ I don't see any other way, and thus I think it a necessary evil to > > improve the long term health of the PHP project. > > > > Feedback on this RFC and different ideas on how to tackle this topic are > > highly appreciated and welcomed. > > > > Best regards, > > > > George P. Banyard > > > > [1] https://github.com/Girgias/error-control-operator-exceptions-rfc > > [2] Draft RFC for throw_on_error declare > > https://github.com/Girgias/php-rfc-throw-on-error-declare > > > > as the I/O API has been revamped within the SPL extension but the > usage of the traditional I/O functions remains the de facto standard > within the community. > > I don't think that this is really an argument for anything. The SPL > options aren't obvious - I would wager that many, most even, PHP > developers barely even know SPL exists. The SPL options aren't pushed > anywhere in the manual that I'm aware of (for example, the manual page > for dir() doesn't even mention FilesystemIterator / DirecrtoryIterator > in any way). >
Maybe, or maybe redesigning an API and rewriting code is suboptimal. But maybe it's also the fact that the documentation doesn't signal the alternatives enough due to lack of documentation maintainers which apparently you don't think it is an issue but I address this below. But in any ways there are over 2500 error/warning/notices in bundled extensions, it is *not* just an I/O issue. But the I/O functions do have somewhat of an alternative which has failed, reasons for that are up to debate.
> Many developers are already using Safe and similar libraries to get > "standard library but with exceptions". If this was available in core > and at least prominently mentioned, if not recommended in the manual > (could we have a "note box" that's not quite a deprecation notice, but a > "we strongly urge you to consider this method" in a similar fashion, if > we don't already?) > > If the manual did a similarly better job of recommending SPL ways of > doing things, I'm sure they'd get used more too. > > Would it make sense in some areas such as file operations to have more > "topic oriented" documentation than the current pure function / class > listing methodology the manual currently uses? (This might make it > easier to point out alternatives or make recommendations) >
The docs are already arranged in "topic oriented" way, look at the function reference page: https://www.php.net/manual/en/funcref.php
> On a related note I dislike "documentation burden" as an argument > against improvements. I obviously understand "open source, volunteers, > translations, etc" but I've heard this a few times now as an argument > against fixing various issues (another example is that many functions in > the manual document that they can return false, but there's absolutely > no explanation as to when this can occur except a single paragraph that > lives on its own page that nobody is ever likely to find if they don't > already know it exists and you can't tell which functions it actually > applies to even if you do). Obviously the project doesn't, but if you > followed this for everything (to the extreme), you'd never introduce any > new functionality because it would mean adding more documentation pages. > If this is an issue, does the project need to consider if there are > better ways to handle documentation? >
The matter of fact is that at this time there is mainly 1 person which solely works on the documentation, and that is Christoph M. Becker (aka cmb) with some occasional contribution from other individuals (me included) even with an issue tracker we are far from having all the changes for PHP 8 documented, and even some PHP 7 behaviour is not documented. So documentation burden is a thing, should it prevent feature additions to the langage? Obviously not, and we mostly deal with this "just" fine as for the docs of the major PHP 8 features were written by their respective RFC authors. A big reason why there was no documentation for false return in the signature is that until recently we did *not* have the capability to display union types via the Doc render (PhD), this is now being corrected but is a tedious job of syncing the docs from the officials stubs to also sync named arguments.
> Are there things the project could implement to improve documentation > contributions and recruit more translators (something along the lines of > "bug days" or "Season of Docs"; this might be easier to implement now > that the docs are in Git(Hub)) >
It is for certain easier to review doc patches now that it's on git with a mirror on GitHub, and we do get contributions but no where near the amount needed to tackle all of the doc bugs, and other issues.
> With regards to the suggested implementations, I would prefer the > improved library with exceptions option. I wouldn't like to see yet > another method of error handling introduced to the standard library > (such as the Go 2 returns method) - it already has too many. Things have > been moving in a good direction recently with everything moving toward > Throwables. I think reversing that trend is a mistake. >
I have at this time no intention of bringing forwards such a proposal, and I don't see how adding a way of handling errors differently would reverse the trend of moving things to Throwables, the point of such an alternative error handling mechanisms is to make dealing with Throwables easiers in situations where they might be more expects, such in low level I/O code.
> Potentially crazy thought: Running with the "improved standard library" > idea, could this be made easier for developers to use by implementing a > "use fallback namespace" statement. While PHP currently falls back to > root / namespace, if the new standard library were - purely for example, > I'm sure others can come up with a better name - under the namespace > "/PHP/standard/", developers could add "use fallback namespace > /PHP/standard/;" to the top of their scripts along with the other use > statements, and PHP would then try that namespace before falling back > further to / when encountering undefined classes. >
Until the whole namespace debacle is sorted in some shape or form, this idea is dead in the water. Moreover, I'm having trouble understanding how it would interact with a call to a function which doesn't exist in that fallback namespace such a strlen(), would it first look in the fallback namespace (potentially multiple fallbacks) before looking back into the global one or? Best, George P. Banyard

Christoph Becker

5 years ago
On 04.03.2021 at 18:46, G. P. B. wrote:
> On Thu, 4 Mar 2021 at 16:06, AllenJB <php.lists@allenjb.me.uk> wrote: > >> On a related note I dislike "documentation burden" as an argument >> against improvements. I obviously understand "open source, volunteers, >> translations, etc" but I've heard this a few times now as an argument >> against fixing various issues (another example is that many functions in >> the manual document that they can return false, but there's absolutely >> no explanation as to when this can occur except a single paragraph that >> lives on its own page that nobody is ever likely to find if they don't >> already know it exists and you can't tell which functions it actually >> applies to even if you do). Obviously the project doesn't, but if you >> followed this for everything (to the extreme), you'd never introduce any >> new functionality because it would mean adding more documentation pages. >> If this is an issue, does the project need to consider if there are >> better ways to handle documentation? >> > > The matter of fact is that at this time there is mainly 1 person which > solely > works on the documentation, and that is Christoph M. Becker (aka cmb) > with some occasional contribution from other individuals (me included) > even with an issue tracker we are far from having all the changes for PHP 8 > documented, and even some PHP 7 behaviour is not documented. > So documentation burden is a thing, should it prevent feature additions to > the langage? Obviously not, and we mostly deal with this "just" fine as for > the docs of the major PHP 8 features were written by their respective RFC > authors. > > A big reason why there was no documentation for false return in the > signature is that until recently we did *not* have the capability to display > union types via the Doc render (PhD), this is now being corrected but is > a tedious job of syncing the docs from the officials stubs to also sync > named arguments.
Allen's point is about the undocumented return values when calling functions with unexpected parameter types (e.g. calling strlen() on an object). There has been quite some discussion about this over the years, mostly on the docs mailing list, and I still don't think this should be documented for each function individually, because it is by definition *undefined* behavior. If it was defined behavior, we could not have elevated this to TypeErrors in PHP 8.0 due to the massive BC break. The fact that this documentation would take years (assuming the current bandwidth) is secondary. Regarding syncing the docs form the official stubs: Máté did a great job of semi-automating this, so it isn't *that* much work anymore, but in my opinion it is important to also keep the documentation correct for PHP 7, and this requires a lot of manual review, and not rarely looking up the actual behavior from the implementation – that is quite some work, and the reviewer's constant reminder how incomplete and out-dated large parts of the manual actually are.
-- Christoph M. Becker

Girgias

5 years ago
On Thu, 4 Mar 2021 at 21:53, Christoph M. Becker <cmbecker69@gmx.de> wrote:
> On 04.03.2021 at 18:46, G. P. B. wrote: > > > On Thu, 4 Mar 2021 at 16:06, AllenJB <php.lists@allenjb.me.uk> wrote: > > > >> On a related note I dislike "documentation burden" as an argument > >> against improvements. I obviously understand "open source, volunteers, > >> translations, etc" but I've heard this a few times now as an argument > >> against fixing various issues (another example is that many functions in > >> the manual document that they can return false, but there's absolutely > >> no explanation as to when this can occur except a single paragraph that > >> lives on its own page that nobody is ever likely to find if they don't > >> already know it exists and you can't tell which functions it actually > >> applies to even if you do). Obviously the project doesn't, but if you > >> followed this for everything (to the extreme), you'd never introduce any > >> new functionality because it would mean adding more documentation pages. > >> If this is an issue, does the project need to consider if there are > >> better ways to handle documentation? > >> > > > > The matter of fact is that at this time there is mainly 1 person which > > solely > > works on the documentation, and that is Christoph M. Becker (aka cmb) > > with some occasional contribution from other individuals (me included) > > even with an issue tracker we are far from having all the changes for > PHP 8 > > documented, and even some PHP 7 behaviour is not documented. > > So documentation burden is a thing, should it prevent feature additions > to > > the langage? Obviously not, and we mostly deal with this "just" fine as > for > > the docs of the major PHP 8 features were written by their respective RFC > > authors. > > > > A big reason why there was no documentation for false return in the > > signature is that until recently we did *not* have the capability to > display > > union types via the Doc render (PhD), this is now being corrected but is > > a tedious job of syncing the docs from the officials stubs to also sync > > named arguments. > > Allen's point is about the undocumented return values when calling > functions with unexpected parameter types (e.g. calling strlen() on an > object). There has been quite some discussion about this over the > years, mostly on the docs mailing list, and I still don't think this > should be documented for each function individually, because it is by > definition *undefined* behavior. If it was defined behavior, we could > not have elevated this to TypeErrors in PHP 8.0 due to the massive BC > break. The fact that this documentation would take years (assuming the > current bandwidth) is secondary. >
Ah right, yeah I don't think those should be documented as it is UB, and iirc it usually throws an E_WARNING with a null return that's why I got confused by the usage of "false return", apologies.
> Regarding syncing the docs form the official stubs: Máté did a great job > of semi-automating this, so it isn't *that* much work anymore, but in my > opinion it is important to also keep the documentation correct for PHP > 7, and this requires a lot of manual review, and not rarely looking up > the actual behavior from the implementation – that is quite some work, > and the reviewer's constant reminder how incomplete and out-dated large > parts of the manual actually are. >
> -- > Christoph M. Becker >
Yes agreed, and I know Maté and you have been working on this a lot, keeping up the French translation up to date with those changes is challenging at times because it's not just the function signature change but there are various amendments to the documentation as a whole. Yesterday I worked on updating the OpenSSL docs and it took me about 3h30 to perform the syncing process. George P. Banyard

Rowan Collins

5 years ago
On 04/03/2021 14:08, G. P. B. wrote:
> This new RFC which I'm proposing is to extend the capability of the error > control operator @ to not just suppress diagnostic messages but also > exceptions. > It can currently be found on GitHub: [1] > https://github.com/Girgias/error-control-operator-exceptions-rfc
Hi George, This is a really creative approach to this thorny problem, and I think I like it, although I'm still working through the implications in my head. One thing I'd like to call out is that this could be useful in its own right, outside of migration strategies. One of the big downsides of exceptions is that they always cause control to jump somewhere else, even when you'd rather they didn't. Joe Duffy in an interesting blog post [1] about error handling strategies refers to it as "control-flow rather than dataflow". For instance, if you start with this: $foo = doSomething() + $bar; If doSomething() throws an exception, and you want to default to just $bar, you have to write this: try {    $foo = doSomething() + $bar; } catch ( SomeException $e ) {    $foo = $bar; } What you really want is to catch the exception, but not break the flow. With this proposal you could: $foo = ( @<SomeException>doSomething() ?? 0 ) + $offset; Which leads me to suggest changing this:
> As such @<\Throwable>expression and @expression are identical.
To this:
> When a class list is given, the operator will not suppress raised
errors (E_WARNING, E_NOTICE, etc).  So @<\Throwable>expression will suppress all possible Exceptions, it does not have the same behaviour as @expression. This makes the operator useful even in situations where you want normal error handling behaviour (e.g. logging) for Warnings and Notices, but want to force an exception back into "dataflow style". [1] http://joeduffyblog.com/2016/02/07/the-error-model/ Regards,
-- Rowan Tommins [IMSoP]

Mike Schinkel

5 years ago
> On Mar 4, 2021, at 9:08 AM, G. P. B. <george.banyard@gmail.com> wrote: > > Hello internals, > > This new RFC which I'm proposing is to extend the capability of the error > control operator @ to not just suppress diagnostic messages but also > exceptions. > It can currently be found on GitHub: [1] > https://github.com/Girgias/error-control-operator-exceptions-rfc
Reading it several times, it is still not clear to me what the following means from the Proposal section: ------------------------- Add the following syntax @<union_class_list> to suppress only the exceptions within the class list, this is similar to: try { expression } catch (union_class_list) {} As such @<\Throwable>expression and @expression are identical. ------------------------- Specifically: 1. What @<union_class_list> means and what it would look like in practice, 2. What catch(union_class_list) would look like in practice, 3. What @<\Throwable>expression means and what it would look like in practice, and 4. Can you provide a few concrete code examples, please?
> The main motivation for this is to provide a path to migrate in a backwards > compatible manner away from diagnostics such as E_WARNING to the use of > exceptions without breaking 99% of PHP code which has been written in the > last 25years.
I am not clear what you mean by "providing a path to migrate in a BC manner" here. Would this require developers to prefix all functions calls with @ for functions changed in a future version of PHP to throw exceptions instead of returning values, assuming they do not have the green light from their stakeholders to make more substantive changes to their code? IOW, are you proposing a requirement to change existing code but in a form that could be (almost?) completely automated? Is that the how you are envisioning this aspect of BC to work?
> This proposal on it's own would not be sufficient to trigger such a change > for extensions but in combination with another proposal to introduce a > `throw_on_error` declare [2] it could provide a bridge for a gradual > transition to the use of more exceptions internally.
Would you also consider adding a reciprocal `error_on_exception` declare?
> Although I'm not thrilled with the idea of shoving more functionality into > @ I don't see any other way, and thus I think it a necessary evil to > improve the long term health of the PHP project.
What do you see as the downside of shoving more functionality into @? Is the concern anything more than making the source for PHP more complicated to maintain?
> Feedback on this RFC and different ideas on how to tackle this topic are > highly appreciated and welcomed. > > Best regards, > > George P. Banyard > > [1] https://github.com/Girgias/error-control-operator-exceptions-rfc > [2] Draft RFC for throw_on_error declare > https://github.com/Girgias/php-rfc-throw-on-error-declare
-Mike

Rowan Collins

5 years ago
On 05/03/2021 04:26, Mike Schinkel wrote:
> 1. What @<union_class_list> means and what it would look like in practice, > 2. What catch(union_class_list) would look like in practice, > 3. What @<\Throwable>expression means and what it would look like in practice, and > 4. Can you provide a few concrete code examples, please?
I think I can help out here. "union_class_list" is just referring to the fact that a catch clause can (as of PHP 7.1) list multiple exception classes in it, using the same syntax as union types: "catch(FooException|BarException $e)". So an example would look like this: $foo = @<FileNotFoundException|InsufficientPermissionException>fopen($bar, 'r'); Which translates to: try { $foo = fopen($bar, 'r'); } catch (FileNotFoundException|InsufficientPermissionException) { $foo = null; }
> I am not clear what you mean by "providing a path to migrate in a BC manner" here. Would this require developers to prefix all functions calls with @ for functions changed in a future version of PHP to throw exceptions instead of returning values, assuming they do not have the green light from their stakeholders to make more substantive changes to their code?
Rather than "having the green light from their stakeholders", I'd focus on the more straight-forward "want upgrading to be as easy as possible". The two advantages that I see in using @ specifically for this are: 1. It is valid syntax in existing versions of PHP, so code using it can be compatible with multiple versions. 2. A lot of people already use it with functions like fopen() to suppress the expected warning, so would have to make no change at all. The problem is that not everybody does prefix, say, fopen() with an @. Some people just live with the noise in their logs of the occasional Warning; others use an alternative mechanism to suppress it, such as wikimedia/at-ease [https://packagist.org/packages/wikimedia/at-ease] That means a lot of people would still need to change their code if fopen() started throwing exceptions, weakening advantage #2. If you make people opt into exceptions, e.g. using declare(throw_on_error=1) then you actually lose *both* advantages: 1. Every file you add the new declare() line to will no longer run on older versions of PHP. 2. Since you're changing every file anyway, in a non-compatible way, you can do some find-and-replace at the same time. For instance, changing "if(@fopen($filename))" into "if(try(fopen($filename)))". I'm also not convinced a file-level opt-in is a sensible long-term strategy. The risk of writing code assuming one error style in a file actually set to the other seems too high. The more I think about it, the more I get the feeling that while this proposal has some great ideas, it hasn't got the combination quite right yet. Regards,
-- Rowan Tommins [IMSoP]

Girgias

5 years ago
On Thu, 4 Mar 2021 at 22:05, Rowan Tommins <rowan.collins@gmail.com> wrote:
> On 04/03/2021 14:08, G. P. B. wrote: > > This new RFC which I'm proposing is to extend the capability of the error > > control operator @ to not just suppress diagnostic messages but also > > exceptions. > > It can currently be found on GitHub: [1] > > https://github.com/Girgias/error-control-operator-exceptions-rfc > > > Hi George, > > This is a really creative approach to this thorny problem, and I think I > like it, although I'm still working through the implications in my head. > > > One thing I'd like to call out is that this could be useful in its own > right, outside of migration strategies. > > One of the big downsides of exceptions is that they always cause control > to jump somewhere else, even when you'd rather they didn't. Joe Duffy in > an interesting blog post [1] about error handling strategies refers to > it as "control-flow rather than dataflow". >
Took me a while to read this article, which was very interesting.
> For instance, if you start with this: > > $foo = doSomething() + $bar; > > If doSomething() throws an exception, and you want to default to just > $bar, you have to write this: > > try { > $foo = doSomething() + $bar; > } > catch ( SomeException $e ) { > $foo = $bar; > } > > What you really want is to catch the exception, but not break the flow. > With this proposal you could: > > $foo = ( @<SomeException>doSomething() ?? 0 ) + $offset; > > > Which leads me to suggest changing this: > > > As such @<\Throwable>expression and @expression are identical. > > To this: > > > When a class list is given, the operator will not suppress raised > errors (E_WARNING, E_NOTICE, etc). So @<\Throwable>expression will > suppress all possible Exceptions, it does not have the same behaviour as > @expression. > > This makes the operator useful even in situations where you want normal > error handling behaviour (e.g. logging) for Warnings and Notices, but > want to force an exception back into "dataflow style". >
This is an interesting idea, and relatively easy to change with my current PoC. However, in that case investigating how to prevent the creation of the exception altogether is something that will need to be investigated as the creation of an exception remains expensive On Sat, 6 Mar 2021 at 13:57, Rowan Tommins <rowan.collins@gmail.com> wrote:
> That means a lot of people would still need to change their code if > fopen() started throwing exceptions, weakening advantage #2. > > > If you make people opt into exceptions, e.g. using > declare(throw_on_error=1) then you actually lose *both* advantages: > > 1. Every file you add the new declare() line to will no longer run on > older versions of PHP. > 2. Since you're changing every file anyway, in a non-compatible way, you > can do some find-and-replace at the same time. For instance, changing > "if(@fopen($filename))" into "if(try(fopen($filename)))". > > I'm also not convinced a file-level opt-in is a sensible long-term > strategy. The risk of writing code assuming one error style in a file > actually set to the other seems too high. >
Frankly I would prefer this to be part of an edition mechanism as I would not want this to be a permanent addition to the language due to the disadvantages that you've listed which I am aware of. But until such a mechanism is introduced into PHP, a declare statement is the best next thing that I can think of.
> The more I think about it, the more I get the feeling that while this > proposal has some great ideas, it hasn't got the combination quite right > yet. >
And that's why I'm publishing it on the list, because the issue is rather complicated and I don't think I can figure it out on my own.
> Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
Best regards, George P. Banyard

Girgias

5 years ago
As Rowan has addressed your first points, I'll skip them but will add a code example to clarify in the RFC. On Fri, 5 Mar 2021 at 04:26, Mike Schinkel <mike@newclarity.net> wrote:
> > This proposal on it's own would not be sufficient to trigger such a > change > > for extensions but in combination with another proposal to introduce a > > `throw_on_error` declare [2] it could provide a bridge for a gradual > > transition to the use of more exceptions internally. > > Would you also consider adding a reciprocal `error_on_exception` declare? >
I would not, as diagnostics (I've started to really despise the wording error/traditional error for E_NOTICE/E_WARNING and co) can always be elevated back to an exception by using a custom error handler.Now in theory the opposite is also true you can set an exception handler and raise an E_WARNING, but this is mostly a useless operation as you're already at the top of the execution stack. Because of that, any time a diagnostic might be emitted the VM needs to perform extra checks to see if it wasn't elevated to an exception and perform some special care handling.As such a declare which would toggle all exceptions to diagnostics is a very bad idea IMHO.Even if this is just limited to functions/methods and not language constructs, emitting a diagnostic is usually subpar as to analyse an error one must do extra steps (reading error_get_last() and branching, etc.)It is true that exceptions can be overused/abused, but they are IMHO far superior to diagnostics.
> Although I'm not thrilled with the idea of shoving more functionality into > > @ I don't see any other way, and thus I think it a necessary evil to > > improve the long term health of the PHP project. > > What do you see as the downside of shoving more functionality into @? Is > the concern anything more than making the source for PHP more complicated > to maintain? > >
Other than the BC break I think there is also the fact that the @ operator has a "bad" reputation and users went to great lengths to *not* use it by utilizing various tricks. And starting now to *promote* the usage of it again could be seen as a net negative by many people, especially as being able to use it to completely ignore any sort of Throwable error (be it a subclass of Error which should probably never be caught and ignored, or a subclass of Exception where it usually would make sense) in such an "easy" manner could lead to overusing exceptions for dataflow although exceptions (at least how my PoC is currently implemented) are still expensive to create just to be tossed away immediately. Best regards, George P. Banyard

Mike Schinkel

5 years ago
> On Mar 6, 2021, at 10:30 AM, G. P. B. <george.banyard@gmail.com> wrote: > > As Rowan has addressed your first points, I'll skip them but will add a code example to clarify in the RFC. > > On Fri, 5 Mar 2021 at 04:26, Mike Schinkel <mike@newclarity.net <mailto:mike@newclarity.net>> wrote: > > This proposal on it's own would not be sufficient to trigger such a change > > for extensions but in combination with another proposal to introduce a > > `throw_on_error` declare [2] it could provide a bridge for a gradual > > transition to the use of more exceptions internally. > > Would you also consider adding a reciprocal `error_on_exception` declare? > > I would not, as diagnostics (I've started to really despise the wording > error/traditional error for E_NOTICE/E_WARNING and co) can always be elevated > back to an exception by using a custom error handler.Now in theory the > opposite is also true you can set an exception handler and raise an E_WARNING, > but this is mostly a useless operation as you're already at the top of the > execution stack.
Thank you for responding to this. However, throwing a traditional error was not was I was suggesting although in hindsight my choice of declare name would indicate exactly that. What I was suggesting for have a way to tell all functions that throw Exceptions to simply return instead. But after further consideration, for that to be useful I realized that such an approach would require more than just a directive and that is what I emailed you privately to consider.
> Because of that, any time a diagnostic might be emitted the VM needs to > perform extra checks to see if it wasn't elevated to an exception and perform > some special care handling.As such a declare which would toggle all exceptions > to diagnostics is a very bad idea IMHO.Even if this is just limited to > functions/methods and not language constructs, emitting a diagnostic is usually > subpar as to analyse an error one must do extra steps (reading error_get_last() > and branching, etc.)It is true that exceptions can be overused/abused, > but they are IMHO far superior to diagnostics. > > > Although I'm not thrilled with the idea of shoving more functionality into > > @ I don't see any other way, and thus I think it a necessary evil to > > improve the long term health of the PHP project. > > What do you see as the downside of shoving more functionality into @? Is the concern anything more than making the source for PHP more complicated to maintain? > > > Other than the BC break I think there is also the fact that the @ operator > has a "bad" reputation and users went to great lengths to *not* use it by > utilizing various tricks. And starting now to *promote* the usage of it again > could be seen as a net negative by many people, especially as being able to > use it to completely ignore any sort of Throwable error (be it a subclass > of Error which should probably never be caught and ignored, or a subclass > of Exception where it usually would make sense) in such an "easy" manner > could lead to overusing exceptions for dataflow although exceptions > (at least how my PoC is currently implemented) are still expensive to create > just to be tossed away immediately.
Ah, good points. Thanks. Seems like there is a need to be able to say "Don't throw the exception, just return it to be so I can handle it immediately" but not require a minimum of five lines of try{}catch{} construct, especially if in this special case generating the call stack was omitted because it would clearly not be needed...? -Mike

Larry Garfield

5 years ago
On Thu, Mar 4, 2021, at 8:08 AM, G. P. B. wrote:
> Hello internals, > > This new RFC which I'm proposing is to extend the capability of the error > control operator @ to not just suppress diagnostic messages but also > exceptions. > It can currently be found on GitHub: [1] > https://github.com/Girgias/error-control-operator-exceptions-rfc > > The main motivation for this is to provide a path to migrate in a backwards > compatible manner away from diagnostics such as E_WARNING to the use of > exceptions without breaking 99% of PHP code which has been written in the > last 25years. > > This proposal on it's own would not be sufficient to trigger such a change > for extensions but in combination with another proposal to introduce a > `throw_on_error` declare [2] it could provide a bridge for a gradual > transition to the use of more exceptions internally. > > Although I'm not thrilled with the idea of shoving more functionality into > @ I don't see any other way, and thus I think it a necessary evil to > improve the long term health of the PHP project. > > Feedback on this RFC and different ideas on how to tackle this topic are > highly appreciated and welcomed. > > Best regards, > > George P. Banyard > > [1] https://github.com/Girgias/error-control-operator-exceptions-rfc > [2] Draft RFC for throw_on_error declare > https://github.com/Girgias/php-rfc-throw-on-error-declare
My first thought is that if you're throwing away exceptions, you're therefore performing an expensive operation (generating a backtrace for the exception) that will then be discarded, and thus is wasted effort. If people start using this frequently as a short-hand that allows exceptions as a bail-out flow contrl (whether that's good or bad, overall), that means you could end up with unexpectedly slow code that generates lots of expensive exceptions for no purpose. My first thought would be to ask if it's possible to set some contextual flag when @<Foo> is used, such that code executed in that scope will not generate a backtrace and instead throw some kind of thin exception that has only the cheap bits in it, making it less expensive. Of course, I realize that may also end up encouraging people to use exceptions for flow control, which is not ideal. Basically, my concern is that making this too easy to do: $val = @<\Throwable> something() ?? 0; will hide some nasty and hard to resolve performance bugs if something() ends up throwing a lot as a matter of course. --Larry Garfield

Rowan Collins

5 years ago
On 06/03/2021 18:00, Larry Garfield wrote:
> My first thought is that if you're throwing away exceptions, you're therefore performing an expensive operation (generating a backtrace for the exception) that will then be discarded, and thus is wasted effort.
I think regardless of any new syntax, this cost is something that needs to be looked into if we want to use exceptions for anything but the most extreme errors. If I'm catching a FileAccessDeniedException, the details of every framework function and middleware handler in my call stack probably aren't relevant, so being able to skip that overhead would be great. Would it be possible to build up the stack trace lazily, as the stack is unwound? Then if ->getTrace() is called, grab the rest of the stack, which will still be current anyway. In my head, it would look something like this, only at the engine level rather than an actual finally block: try {     ...     throw new Exception; // here, the current line number is captured, but nothing else     ... } finally {     // Save trace information for current frame before returning } Then further up the stack: try {    something_that_throws(); } catch ( Exception $e ) {    echo $e->getTraceAsString(); // trace is currently incomplete, but the remaining levels are the trace of the current line anyway, so we can put the cost here } Does that make any sense? Regards,
-- Rowan Tommins [IMSoP]

Mike Schinkel

5 years ago
> On Mar 6, 2021, at 1:00 PM, Larry Garfield <larry@garfieldtech.com> wrote: > > On Thu, Mar 4, 2021, at 8:08 AM, G. P. B. wrote: >> Hello internals, >> >> This new RFC which I'm proposing is to extend the capability of the error >> control operator @ to not just suppress diagnostic messages but also >> exceptions. >> It can currently be found on GitHub: [1] >> https://github.com/Girgias/error-control-operator-exceptions-rfc >> >> The main motivation for this is to provide a path to migrate in a backwards >> compatible manner away from diagnostics such as E_WARNING to the use of >> exceptions without breaking 99% of PHP code which has been written in the >> last 25years. >> >> This proposal on it's own would not be sufficient to trigger such a change >> for extensions but in combination with another proposal to introduce a >> `throw_on_error` declare [2] it could provide a bridge for a gradual >> transition to the use of more exceptions internally. >> >> Although I'm not thrilled with the idea of shoving more functionality into >> @ I don't see any other way, and thus I think it a necessary evil to >> improve the long term health of the PHP project. >> >> Feedback on this RFC and different ideas on how to tackle this topic are >> highly appreciated and welcomed. >> >> Best regards, >> >> George P. Banyard >> >> [1] https://github.com/Girgias/error-control-operator-exceptions-rfc >> [2] Draft RFC for throw_on_error declare >> https://github.com/Girgias/php-rfc-throw-on-error-declare > > My first thought is that if you're throwing away exceptions, you're therefore performing an expensive operation (generating a backtrace for the exception) that will then be discarded, and thus is wasted effort. > > If people start using this frequently as a short-hand that allows exceptions as a bail-out flow contrl (whether that's good or bad, overall), that means you could end up with unexpectedly slow code that generates lots of expensive exceptions for no purpose. > > My first thought would be to ask if it's possible to set some contextual flag when @<Foo> is used, such that code executed in that scope will not generate a backtrace and instead throw some kind of thin exception that has only the cheap bits in it, making it less expensive. Of course, I realize that may also end up encouraging people to use exceptions for flow control, which is not ideal.
If a thin exception were used, let's say maybe Exception were modified to move message, code, file and line to a Notice class and then Exception extended Notice then would using Notice for flow control actually still be using exceptions? Or would it not instead be using error handling more like how Go uses error handling, with objects that simply provide access to the information that caused the calling function to not complete as expected?
> > Basically, my concern is that making this too easy to do: > > $val = @<\Throwable> something() ?? 0; > > will hide some nasty and hard to resolve performance bugs if something() ends up throwing a lot as a matter of course. > > --Larry Garfield
-Mike