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
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-rfcThe main motivation for this is to provide a path to migrate in a backwards
compatible manner away from diagnostics such asE_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.
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-rfcThe main motivation for this is to provide a path to migrate in a
backwards
compatible manner away from diagnostics such asE_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-declareas 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
fordir()
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
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
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. callingstrlen()
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
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]
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:
- What @<union_class_list> means and what it would look like in practice,
- What catch(union_class_list) would look like in practice,
- What @<\Throwable>expression means and what it would look like in practice, and
- 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 asE_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
- What @<union_class_list> means and what it would look like in practice,
- What catch(union_class_list) would look like in practice,
- What @<\Throwable>expression means and what it would look like in practice, and
- 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:
- It is valid syntax in existing versions of PHP, so code using it can
be compatible with multiple versions. - 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:
- Every file you add the new declare() line to will no longer run on
older versions of PHP. - 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]
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-rfcHi 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
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:
- Every file you add the new declare() line to will no longer run on
older versions of PHP.- 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]--
To unsubscribe, visit: https://www.php.net/unsub.php
Best regards,
George P. Banyard
As Rowan has addressed your first points, I'll skip them but will add a
code example to clarify in the RFC.
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
As Rowan has addressed your first points, I'll skip them but will add a code example to clarify in the RFC.
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 (readingerror_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
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-rfcThe main motivation for this is to provide a path to migrate in a backwards
compatible manner away from diagnostics such asE_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
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]
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-rfcThe main motivation for this is to provide a path to migrate in a backwards
compatible manner away from diagnostics such asE_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-declareMy 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