-
-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trigger E_USER_ERROR on unhandled exceptions #170
Trigger E_USER_ERROR on unhandled exceptions #170
Conversation
a025841
to
e707f7e
Compare
e707f7e
to
66aaecc
Compare
src/Internal/RejectedPromise.php
Outdated
$message .= ' raised in ' . $this->reason->getFile() . ' on line ' . $this->reason->getLine(); | ||
$message .= PHP_EOL . $this->reason->getTraceAsString() . PHP_EOL; | ||
|
||
fatalError($message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rejections in done()
are also unhandled rejections and should probably use the same error message format.
promise/src/Internal/FulfilledPromise.php
Line 54 in 57d86e5
return fatalError($exception); |
https://github.com/reactphp/promise/blob/master/src/Internal/RejectedPromise.php#L45
https://github.com/reactphp/promise/blob/master/src/Internal/RejectedPromise.php#L55
Maybe we can rename fatalError()
to something like unhandledRejectionError()
and generate the message there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@WyriHaximus Thanks for looking into this again! I agree that any unhandled exceptions should cause the program to report a hard error and then die()
.
This is definitely a BC break, so this PR only targets the upcoming Promise v3 release branch. Once we can come up with decent solution, we should look into providing a better upgrade path for the Promise v2 release branch, e.g. printing a soft warning possibly with an option to turn this off etc.
Note that the error handler passed to set_error_handler()
may silently discard the error and not die()
internally. It's my understanding we should explicitly die()
in this case:
I also don't feel the global error handler is the best place to deal with unhandled rejections. I think the global exception handler might be a better place, but it looks like there's no (sane) way to explicitly call this handler. Here are some of my experiments:
66aaecc
to
7d65e33
Compare
As discussed with @clue, adding a test case to spawn a child process, force it to have an unhandled rejected promise and expect a |
7d65e33
to
0c8fb51
Compare
Had a long chat with @clue about this today. And we came to the conclusion that killing off the process in 3.0 is to soon. It would mean a hard migration, and while we will have our own projects ready by then, the ecosystem might be caught off guard by it. What we want to do instead, is still be in your face annoying about this but not kill the process. We're still figuring out the best way for that as we can't use the exception handler for this, and we want to provide users with the full context plus a way to catch any of these unhandled errors. This possibly comes down to providing a singleton accepting a handler. |
// set dummy handler and return previous handler | ||
$handler = set_exception_handler(static function (Throwable $throwable) { | ||
throw $throwable; | ||
}); | ||
|
||
// use dummy handler when no original handler is available | ||
if ($handler === null) { | ||
$handler = set_exception_handler(null); | ||
} | ||
|
||
set_exception_handler(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO you need to restore the original handler there, not wipe it.
// set dummy handler and return previous handler | |
$handler = set_exception_handler(static function (Throwable $throwable) { | |
throw $throwable; | |
}); | |
// use dummy handler when no original handler is available | |
if ($handler === null) { | |
$handler = set_exception_handler(null); | |
} | |
set_exception_handler(null); | |
// set dummy handler and return previous handler | |
$handler = set_exception_handler(static function (Throwable $throwable) { | |
throw $throwable; | |
}); | |
// use dummy handler when no original handler is available | |
if ($handler === null) { | |
$handler = set_exception_handler(null); | |
} else { | |
// restore original handler | |
set_exception_handler($handler); | |
} |
Largely based on @clue's work at clue-labs@0feb517 to trigger an error when a rejected promise hasn't been handled.
Closes #87