-
Notifications
You must be signed in to change notification settings - Fork 10
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
Accept Throwable
as rejection reason
#31
base: 1.x
Are you sure you want to change the base?
Accept Throwable
as rejection reason
#31
Conversation
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.
thank you for looking into this.
i start to think we should revert the widening of #30 for the 1.x version and do the change here as 2.x.
however, i am unsure about the best practices with promises: the AsyncHttpClient is supposed to only do promises for http exceptions and throw all other exceptions. if any other exception is thrown, it could imho make sense to not go through the promise and callbacks because it means some unhandled fatal error has happened that is not supposed to be handled by the stack.
unfortunately i lack experience with the promise pattern to decide which is the right approach.
@@ -34,8 +34,8 @@ public function then(callable $onFulfilled = null, callable $onRejected = null) | |||
|
|||
try { | |||
return new FulfilledPromise($onRejected($this->exception)); |
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.
i think this moves the BC break from our own code to the callable. if the onRejected callback has a type declaration, the fatal error would now happen while calling the callback
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.
Technically speaking, we're not breaking anything that wasn't broken before imho: if the callback did not accept a Throwable
, then it keeps being broken, otherwise we were the ones that were broken, so it didn't matter.
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.
yes, correct. but thats why i wonder if we should do the widening or sharpen that a rejected promise can be about only a subset of exceptions.
@GrahamCampbell @Nyholm i would be glad if you have any insights here. i see that guzzle seems to indeed wrap any exception (though not other throwables) in its rejected promise: https://github.com/guzzle/guzzle/blob/d95d9ab74822c2ca06b31477cd6775a4a299b8e8/src/Client.php#L335 our phpdoc on the php-http async client interface claims we only wrap the http client exceptions in the promise and would directly throw others. is that the right approach? should we adjust the async client interface to pass all exceptions through the promise? currently, the guzzle7-adapter promise wraps any non http client exception into http client exceptions: https://github.com/php-http/guzzle7-adapter/blob/03328049033fc2d9c2b2a93fb5554d519d78ce6e/src/Promise.php#L56 |
I would say yes. As a user, I want the promises to have a consistent behaviour, meaning that in the end I receive a |
we had more discussion in php-http/client-common#234 (comment) - i think we can not suddenly change what class of exception we pass to the rejected callback. and e.g. the guzzle adapter wrapped all exceptions in httplug exceptions to work with that restriction. |
I don't think throwables should be wrapped. Non-exception throwables are code bugs, and typically we want a hard crash. I somewhat regret that guzzle promises made this change in a minor release. I guess I don't massively oppose this, if it's to be made in a major release. |
looking at guzzle adapter, we adapt the guzzle PromiseInterface to our promise like this: https://github.com/php-http/guzzle7-adapter/blob/03328049033fc2d9c2b2a93fb5554d519d78ce6e/src/Promise.php#L56 i have troubles wrapping my head around what we do there but if i understand it correctly, we forward the callbacks directly to the guzzle promise, which violates the phpdoc we do on the async client, we would need to wrap the onRejected with a callback that makes sure the exception is of the right type. if its not a guzzle or psr http exception, i think indeed we should just throw it, as its not something to be expected or handled. |
i spent a lot of time trying to get this to work in php-http/httplug#173 but was not able to work it out. i came to the conclusion that it probably just can't work because we can leave this open if you want to give it another shot, but I will only merge generic annotations if we have a pull request like php-http/httplug#173 that uses this branch here and shows it can actually be used correctly. |
Hi, I was just randomly looking through the code and noticed the clash of exception vs. throwable in the implementation. I thought I could submit a fix while I noticed I'm not the first to have the exact same idea. So I'll just leave my viewpoint here. I must 100% side with @ste93cry in this case. Calling All other exceptions (including type errors arising from callbacks with incompatible arguments) should be thrown in Promise is an abstract concept (not even restricted to http) with 3 states and it must behave the same in all of them. It seems to me you can't but think of promise as This is inconsistent and a clear sign that the current implementation is wrong. This is further strengthened by the fact that other php promise implememtations also behave this way, which was already mentioned. Also javascript promises behave the same. In conclusion, I hope this PR will pass, even if it means 2.0. |
What's in this PR?
The type of the constructor argument of
RejectedPromise
has been widened to accept anyThrowable
. Also, when anError
instance is thrown (e.g. because an unexpected type is passed to the callbacks), the promise is rejected and the chain keeps going on instead of crashing the script.Why?
When
$onFulfilled
or$onRejected
are called, an exception or error can be thrown. In the latter case, the whole script crashes abruptly because thecatch
statement, that should return aRejectedPromise
, accepts only an instance ofException
. Moreover, aRejectedPromise
cannot be constructed from aThrowable
, because the constructor argument has the same issue. Since #30 widened the argument type of the$onRejected
callback, this is now even more evident due to the misleading documentation.Before
After
Checklist