5353function await (PromiseInterface $ promise )
5454{
5555 $ wait = true ;
56- $ resolved = null ;
57- $ exception = null ;
56+ $ resolved = false ;
5857 $ rejected = false ;
58+ $ resolvedValue = null ;
59+ $ rejectedThrowable = null ;
5960
6061 $ promise ->then (
61- function ($ c ) use (&$ resolved , &$ wait ) {
62- $ resolved = $ c ;
62+ function ($ c ) use (&$ resolved , &$ resolvedValue , &$ wait ) {
63+ $ resolvedValue = $ c ;
64+ $ resolved = true ;
6365 $ wait = false ;
6466 Loop::stop ();
6567 },
66- function ($ error ) use (&$ exception , &$ rejected , &$ wait ) {
67- $ exception = $ error ;
68+ function ($ error ) use (&$ rejected , &$ rejectedThrowable , &$ wait ) {
69+ // promise is rejected with an unexpected value (Promise API v1 or v2 only)
70+ if (!$ error instanceof \Exception && !$ error instanceof \Throwable) {
71+ $ error = new \UnexpectedValueException (
72+ 'Promise rejected with unexpected value of type ' . (is_object ($ error ) ? get_class ($ error ) : gettype ($ error ))
73+ );
74+
75+ // avoid garbage references by replacing all closures in call stack.
76+ // what a lovely piece of code!
77+ $ r = new \ReflectionProperty ('Exception ' , 'trace ' );
78+ $ r ->setAccessible (true );
79+ $ trace = $ r ->getValue ($ error );
80+
81+ // Exception trace arguments only available when zend.exception_ignore_args is not set
82+ // @codeCoverageIgnoreStart
83+ foreach ($ trace as $ ti => $ one ) {
84+ if (isset ($ one ['args ' ])) {
85+ foreach ($ one ['args ' ] as $ ai => $ arg ) {
86+ if ($ arg instanceof \Closure) {
87+ $ trace [$ ti ]['args ' ][$ ai ] = 'Object( ' . \get_class ($ arg ) . ') ' ;
88+ }
89+ }
90+ }
91+ }
92+ // @codeCoverageIgnoreEnd
93+ $ r ->setValue ($ error , $ trace );
94+ }
95+
96+ $ rejectedThrowable = $ error ;
6897 $ rejected = true ;
6998 $ wait = false ;
7099 Loop::stop ();
@@ -75,25 +104,25 @@ function ($error) use (&$exception, &$rejected, &$wait) {
75104 // argument does not show up in the stack trace in PHP 7+ only.
76105 $ promise = null ;
77106
107+ if ($ rejected ) {
108+ throw $ rejectedThrowable ;
109+ }
110+
111+ if ($ resolved ) {
112+ return $ resolvedValue ;
113+ }
114+
78115 while ($ wait ) {
79116 Loop::run ();
80117 }
81118
82119 if ($ rejected ) {
83- // promise is rejected with an unexpected value (Promise API v1 or v2 only)
84- if (!$ exception instanceof \Throwable) {
85- $ exception = new \UnexpectedValueException (
86- 'Promise rejected with unexpected value of type ' . (is_object ($ exception ) ? get_class ($ exception ) : gettype ($ exception ))
87- );
88- }
89-
90- throw $ exception ;
120+ throw $ rejectedThrowable ;
91121 }
92122
93- return $ resolved ;
123+ return $ resolvedValue ;
94124}
95125
96-
97126/**
98127 * Execute a Generator-based coroutine to "await" promises.
99128 *
0 commit comments