---- En mié, 11 mar 2020 11:09:13 +0100 Nikita Popov <nikita....@gmail.com> 
escribió ----
 > On Fri, Oct 11, 2019 at 4:11 PM Nikita Popov <nikita....@gmail.com> wrote:
 > 
 > > On Fri, Oct 11, 2019 at 3:47 PM Marcio Almada <marcio.w...@gmail.com>
 > > wrote:
 > >
 > >> Em sex, 11 de out de 2019 às 08:05, Nikita Popov
 > >> <nikita....@gmail.com> escreveu:
 > >> >
 > >> > Hi,
 > >> >
 > >>
 > >> Hello :)
 > >>
 > >> > Currently exit() is implemented using bailout and unclean shutdown,
 > >> which
 > >> > means that we're going to perform a longjmp back to the top-level scope
 > >> and
 > >> > let the memory manager clean up all the memory it knows about. Anything
 > >> not
 > >> > allocated using ZMM is going to leak persistently.
 > >> >
 > >> > For me, one of the most annoying things about this is that we can't
 > >> perform
 > >> > proper leak checks on code using PhpUnit, because it will always exit()
 > >> at
 > >> > the end, which will result in "expected" memory leaks.
 > >> >
 > >> > I think it would be good to switch exit() to work by throwing a magic
 > >> > exception, similar to what Python does. This would allow us to properly
 > >> > unwind the stack, executing finally blocks (which are currently skipped)
 > >> > and perform a clean engine shutdown.
 > >> >
 > >> > Depending on the implementation, we could also allow code to actually
 > >> catch
 > >> > this exception, which may be useful for testing scenarios, as well as
 > >> > long-running daemons.
 > >> >
 > >> > I'm mainly wondering how exactly we'd go about integrating this in the
 > >> > existing exception hierarchy.
 > >>
 > >> > Assuming that it is desirable to allow people
 > >> > to actually catch this exception
 > >> > my first thought would be along these
 > >> > lines:
 > >> >
 > >> > Throwable (convert to abstract class)
 > >> > \-> Exception
 > >> > \-> Error
 > >> > \-> ExitThrowable
 > >> >
 > >> > This does mean though that existing code using catch(Throwable) is
 > >> going to
 > >> > catch exit()s as well. This can be avoided by introducing *yet another*
 > >> > super-class/interface above Throwable, which is something I'd rather
 > >> avoid.
 > >> >
 > >>
 > >> Since you brought python as inspiration, I believe the hierarchy goes
 > >> like this on their land:
 > >>
 > >> BaseException
 > >>  +-- SystemExit
 > >>  +-- KeyboardInterrupt
 > >>  +-- GeneratorExit
 > >>  +-- Exception
 > >>      +-- [kitchen sink]
 > >>
 > >> Being `BaseException` the base class for all built-in exceptions. It
 > >> is not meant to be directly
 > >> inherited by user-defined classes. It 's the equivalent to our
 > >> `Throwable` situation. In this context
 > >> `ExitThrowable -> Throwable ` appears legit.
 > >>
 > >> >
 > >> > Anyone have thoughts on this matter?
 > >> >
 > >>
 > >> Yes. There is an obvious can of worms if I've got this right: `exit()`
 > >> and `die()` would no longer guarantee a
 > >> program to actually terminate in case catching `ExitThrowable` is
 > >> allowed. Python solves this by actually
 > >> having two patterns:
 > >>
 > >> 1. `quit()`, `exit()`, `sys.exit()` are the equivalent to `raise
 > >> SystemExit`, can be caught / interrupted
 > >> 2. `os._exit()`, can't be caught but has a callback mechanism like our
 > >> `register_shutdown_function`,
 > >> see https://docs.python.org/3/library/atexit.html
 > >
 > >
 > > I don't believe atexit applies to os._exit(). In any case, I agree that
 > > this is something we're currently missing -- we should probably add a
 > > pcntl_exit() for this purpose. It should be noted though that this is
 > > really very different from exit(), which is still quite graceful and usable
 > > in a webserver context, while a hypothetical pcntl_exit() would bring down
 > > the server process. As the Python docs mention, the primary use-case would
 > > be exiting from forked processes without going through shutdown, which has
 > > also recently come up in https://github.com/php/php-src/pull/4712.
 > >
 > >
 > >> If we bind `exit()` and `die()` to a catchable exception how would we
 > >> still have the scenario 2 available
 > >> on PHP land without a BCB? :)
 > >>
 > >
 > >> I have one simple suggestion: Introduce `EngineShutdown -> Throwable`,
 > >> bind `exit|die` to it but disallow
 > >> `catch(\EngineShutdown $e)` at compile time. This would allow keeping
 > >> backwards compatibility to
 > >> scenario 2 without messing with our current exception hierarchy.
 > >>
 > >
 > > I think the options are basically:
 > >
 > > 1. Making EngineShutdown implement Throwable, which would make existing
 > > catch(Throwable) catch it -- probably a no-go.
 > >
 > > 2. Making EngineShutdown not implement Throwable, which means that not all
 > > "exceptions" implement the interface, which is rather odd. It still allows
 > > explicitly catching the exit.
 > >
 > > 3. Introducing a function like catch_exit(function() { ... }). This would
 > > still allow catching exits (for phpunit + daemon use cases), but the fact
 > > that this is actually implemented based on an exception would be hidden and
 > > the only way to catch the exit is through this function.
 > >
 > > 4. Don't allow catching exits at all. In this case the exception is just
 > > an implementation detail.
 > >
 > 
 > I've started implementing variant 4 in
 > https://github.com/php/php-src/pull/5243. It uses an internal exception
 > type to implement exit() that cannot be caught.
 > 
 > Finally blocks do get executed, as they should be. This does mean that it
 > is possibly to discard the exit through finally, because control flow
 > performed in finally always wins:
 > 
 > try {
 >     exit;
 > } finally {
 >     (null)->method(); // throw Error
 > }
 > 
 > This snippet will throw an Error exception, with the original exit being
 > discarded.
 > 
 > try {
 >     try {
 >         exit;
 >     } finally {
 >         (null)->method(); // throw Error
 >     }
 > } catch (Error $e) {
 >     // Ignore
 > }
 > 
 > This snippet will catch the Error exception and thus stops unwinding.
 > 
 > I believe this behavior is correct and expected (by which I mean:
 > consistent with finally semantics), but it does mean that exits can be
 > discarded even without having an explicit "catch_exit" function or similar.
 > 
 > Nikita
 > 

Hello,

About this subject:

Nowadays, `register_shutdown_function`* function exists in order to custom your 
 the end of program. However, with this code:

--- CODE ---

<?php
register_shutdown_function( function() {
        echo "\nIn register_shutdown_function";
        new Exception("Exception");
});


try {
    echo "\nIn Try";
    exit();
}catch (\Throwable $e) {
        echo "\nIn Catch";
}

--- /CODE ---

Out is:

--- OUT ---

In Try

In register_shutdown_function

--- /OUT ---

Maybe, The solution to exit with exception is that script ends only if all 
callbacks of `register-shutdown-function` are ended and It's also necessary 
that context is keeped. In this way, previous code output should be:


--- OUT ---

In Try

In register_shutdown_function

In Catch

--- /OUT ---

This would keep backward compatibility.


References:

*https://www.php.net/manual/en/function.register-shutdown-function.php


Regards

--
Manuel Canga

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to