Greetings internals,
While working on rewriting the PHP docs about errors and error handling [1]
I came across a change of behaviour in an edge case of an edge case.
finally blocks are meant to be always executed regardless that an Exception
has been thrown or not, which it does, however a call to exit() (or die()
as they are aliases).
This can be seen with the following example: https://3v4l.org/6Tger
However, there is one case where finally blocks are executed when exit() is
used, namely when a generator has a finally block and exit() is called
during its traversal, an example of this in action can be seen here:
https://3v4l.org/HGKHS
The behaviour of this edge case of an edge case is highly dependent on the
version of PHP where this is run, PHP 5.5, 5.6, 7.0, early version of PHP
7.1, PHP 7.2.0, PHP 7.2.1, and PHP 8.0 all run the finally block on exit().
Later versions of PHP 7.1, 7.2.2 and above and PHP 7.3 and 7.4 all skip the
finally block.
Frankly this is already going to be a mess to document, but this begs the
question is there a "bug" in executing the finally blocks in generators
during a call to exit() or is the "bug" to not execute finally blocks when
exit() is called.
I've CCed the PHP 8.0 RMs as if the consensus is that skipping finally
blocks after a call to exit() is performed it would be wise to change this
behaviour in PHP 8.0 only and land this ASAP, even though it's a BC break.
Interested in hearing your thoughts.
Best regards,
George P. Banyard
Interesting. I'm not sure there's a "correct" answer here, but FWIW on
balance my feeling is the expectation that exit() will immediately
terminate a script (registered shutdown functions and destructors aside)
should take precedence over the expectation that finally blocks will always
execute, just because if you've got an exit/die inside a try block, I think
it is reasonable to expect that you have already done anything that needs
to be done before you get there (i.e. that your intent is for nothing else
to happen), or to consider it a bug (certainly eyebrow raising code smell)
otherwise. It's not the kind of use case finally was conceptually intended
to address. And unlike an explicitly declared and self contained shutdown
function or destructor, this could lead to what is effectively shutdown
code being far removed and in a seemingly-random place in the code in
relation to where the exit call occurs, maybe in a different file and not
obvious to track down.
Dave
Greetings internals,
While working on rewriting the PHP docs about errors and error handling [1]
I came across a change of behaviour in an edge case of an edge case.finally blocks are meant to be always executed regardless that an Exception
has been thrown or not, which it does, however a call to exit() (or die()
as they are aliases).
This can be seen with the following example: https://3v4l.org/6TgerHowever, there is one case where finally blocks are executed when exit() is
used, namely when a generator has a finally block and exit() is called
during its traversal, an example of this in action can be seen here:
https://3v4l.org/HGKHSThe behaviour of this edge case of an edge case is highly dependent on the
version of PHP where this is run, PHP 5.5, 5.6, 7.0, early version of PHP
7.1, PHP 7.2.0, PHP 7.2.1, and PHP 8.0 all run the finally block on exit().
Later versions of PHP 7.1, 7.2.2 and above and PHP 7.3 and 7.4 all skip the
finally block.Frankly this is already going to be a mess to document, but this begs the
question is there a "bug" in executing the finally blocks in generators
during a call to exit() or is the "bug" to not execute finally blocks when
exit() is called.I've CCed the PHP 8.0 RMs as if the consensus is that skipping finally
blocks after a call to exit() is performed it would be wise to change this
behaviour in PHP 8.0 only and land this ASAP, even though it's a BC break.Interested in hearing your thoughts.
Best regards,
George P. Banyard
Executing finally blocks after a die was discussed in
https://externals.io/message/107497 "exit() via exception", but
https://github.com/php/php-src/pull/5243 "Make exit() unwind properly"
wasn't merged in 8.0, just https://github.com/php/php-src/pull/5768 "...
(minimal version)".
The change of behavior for https://3v4l.org/HGKHS "yield - finally" that
occurred in PHP 7.1.14 and 7.2.2 is probably related to
https://bugs.php.net/bug.php?id=75396 "Exit inside generator finally
results in fatal error".
Maybe the behavior changed back in PHP 8.0.0 because of an unexpected
interaction of those two things?
(adding Nikita to the CC list)
--
Guilliam Xavier
Greetings internals,
While working on rewriting the PHP docs about errors and error handling [1]
I came across a change of behaviour in an edge case of an edge case.finally blocks are meant to be always executed regardless that an Exception
has been thrown or not, which it does, however a call to exit() (or die()
as they are aliases).
This can be seen with the following example: https://3v4l.org/6TgerHowever, there is one case where finally blocks are executed when exit() is
used, namely when a generator has a finally block and exit() is called
during its traversal, an example of this in action can be seen here:
https://3v4l.org/HGKHSThe behaviour of this edge case of an edge case is highly dependent on the
version of PHP where this is run, PHP 5.5, 5.6, 7.0, early version of PHP
7.1, PHP 7.2.0, PHP 7.2.1, and PHP 8.0 all run the finally block on exit().
Later versions of PHP 7.1, 7.2.2 and above and PHP 7.3 and 7.4 all skip the
finally block.Frankly this is already going to be a mess to document, but this begs the
question is there a "bug" in executing the finally blocks in generators
during a call to exit() or is the "bug" to not execute finally blocks when
exit() is called.I've CCed the PHP 8.0 RMs as if the consensus is that skipping finally
blocks after a call to exit() is performed it would be wise to change this
behaviour in PHP 8.0 only and land this ASAP, even though it's a BC break.Interested in hearing your thoughts.
Best regards,
George P. Banyard
Hello again,
From my message from two weeks ago, my understanding is that finally blocks
are never supposed to be executed on exit(), and that there is indeed a
bug (regression) with generators.
With PHP 8.0.3RC1 having been released without any reply here from the
people CCed, maybe you should open a bug report?
--
Guilliam Xavier
On Tue, Feb 23, 2021 at 4:52 PM Guilliam Xavier guilliam.xavier@gmail.com
wrote:
Greetings internals,
While working on rewriting the PHP docs about errors and error handling
[1]
I came across a change of behaviour in an edge case of an edge case.finally blocks are meant to be always executed regardless that an
Exception
has been thrown or not, which it does, however a call to exit() (or die()
as they are aliases).
This can be seen with the following example: https://3v4l.org/6TgerHowever, there is one case where finally blocks are executed when exit()
is
used, namely when a generator has a finally block and exit() is called
during its traversal, an example of this in action can be seen here:
https://3v4l.org/HGKHSThe behaviour of this edge case of an edge case is highly dependent on
the
version of PHP where this is run, PHP 5.5, 5.6, 7.0, early version of PHP
7.1, PHP 7.2.0, PHP 7.2.1, and PHP 8.0 all run the finally block on
exit().
Later versions of PHP 7.1, 7.2.2 and above and PHP 7.3 and 7.4 all skip
the
finally block.Frankly this is already going to be a mess to document, but this begs the
question is there a "bug" in executing the finally blocks in generators
during a call to exit() or is the "bug" to not execute finally blocks
when
exit() is called.I've CCed the PHP 8.0 RMs as if the consensus is that skipping finally
blocks after a call to exit() is performed it would be wise to change
this
behaviour in PHP 8.0 only and land this ASAP, even though it's a BC
break.Interested in hearing your thoughts.
Best regards,
George P. Banyard
Hello again,
From my message from two weeks ago, my understanding is that finally blocks
are never supposed to be executed on exit(), and that there is indeed a
bug (regression) with generators.With PHP 8.0.3RC1 having been released without any reply here from the
people CCed, maybe you should open a bug report?
Finally blocks are intended to be always executed when destructors are
executed. The fact that they are not yet executed for exit() outside
generators is a known bug. (For generators, finally is part of the
destructor, which is why the issue does not appear there.)
Regards,
Nikita
On Tue, Feb 23, 2021 at 4:52 PM Guilliam Xavier guilliam.xavier@gmail.com
wrote:Greetings internals,
While working on rewriting the PHP docs about errors and error handling
[1]
I came across a change of behaviour in an edge case of an edge case.finally blocks are meant to be always executed regardless that an
Exception
has been thrown or not, which it does, however a call to exit() (or
die()
as they are aliases).
This can be seen with the following example: https://3v4l.org/6TgerHowever, there is one case where finally blocks are executed when
exit() is
used, namely when a generator has a finally block and exit() is called
during its traversal, an example of this in action can be seen here:
https://3v4l.org/HGKHSThe behaviour of this edge case of an edge case is highly dependent on
the
version of PHP where this is run, PHP 5.5, 5.6, 7.0, early version of
PHP
7.1, PHP 7.2.0, PHP 7.2.1, and PHP 8.0 all run the finally block on
exit().
Later versions of PHP 7.1, 7.2.2 and above and PHP 7.3 and 7.4 all skip
the
finally block.Frankly this is already going to be a mess to document, but this begs
the
question is there a "bug" in executing the finally blocks in generators
during a call to exit() or is the "bug" to not execute finally blocks
when
exit() is called.I've CCed the PHP 8.0 RMs as if the consensus is that skipping finally
blocks after a call to exit() is performed it would be wise to change
this
behaviour in PHP 8.0 only and land this ASAP, even though it's a BC
break.Interested in hearing your thoughts.
Best regards,
George P. Banyard
Hello again,
From my message from two weeks ago, my understanding is that finally
blocks
are never supposed to be executed on exit(), and that there is indeed a
bug (regression) with generators.With PHP 8.0.3RC1 having been released without any reply here from the
people CCed, maybe you should open a bug report?Finally blocks are intended to be always executed when destructors are
executed. The fact that they are not yet executed for exit() outside
generators is a known bug. (For generators, finally is part of the
destructor, which is why the issue does not appear there.)Regards,
Nikita
Thanks for replying. So it seems that I had it all backwards ^^'
For the record, this comment may help understanding:
https://github.com/php/php-src/pull/5243#issuecomment-598664651
--
Guilliam Xavier