53
53
function await (PromiseInterface $ promise )
54
54
{
55
55
$ wait = true ;
56
- $ resolved = null ;
57
- $ exception = null ;
56
+ $ resolved = false ;
58
57
$ rejected = false ;
58
+ $ resolvedValue = null ;
59
+ $ rejectedThrowable = null ;
59
60
60
61
$ promise ->then (
61
- function ($ c ) use (&$ resolved , &$ wait ) {
62
- $ resolved = $ c ;
62
+ function ($ c ) use (&$ resolved , &$ resolvedValue , &$ wait ) {
63
+ $ resolvedValue = $ c ;
64
+ $ resolved = true ;
63
65
$ wait = false ;
64
66
Loop::stop ();
65
67
},
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
+ $ trace = $ r ->getValue ($ error );
79
+
80
+ // Exception trace arguments only available when zend.exception_ignore_args is not set
81
+ // @codeCoverageIgnoreStart
82
+ foreach ($ trace as $ ti => $ one ) {
83
+ if (isset ($ one ['args ' ])) {
84
+ foreach ($ one ['args ' ] as $ ai => $ arg ) {
85
+ if ($ arg instanceof \Closure) {
86
+ $ trace [$ ti ]['args ' ][$ ai ] = 'Object( ' . \get_class ($ arg ) . ') ' ;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ // @codeCoverageIgnoreEnd
92
+ $ r ->setValue ($ error , $ trace );
93
+ }
94
+
95
+ $ rejectedThrowable = $ error ;
68
96
$ rejected = true ;
69
97
$ wait = false ;
70
98
Loop::stop ();
@@ -75,25 +103,25 @@ function ($error) use (&$exception, &$rejected, &$wait) {
75
103
// argument does not show up in the stack trace in PHP 7+ only.
76
104
$ promise = null ;
77
105
106
+ if ($ rejected ) {
107
+ throw $ rejectedThrowable ;
108
+ }
109
+
110
+ if ($ resolved ) {
111
+ return $ resolvedValue ;
112
+ }
113
+
78
114
while ($ wait ) {
79
115
Loop::run ();
80
116
}
81
117
82
118
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 ;
119
+ throw $ rejectedThrowable ;
91
120
}
92
121
93
- return $ resolved ;
122
+ return $ resolvedValue ;
94
123
}
95
124
96
-
97
125
/**
98
126
* Execute a Generator-based coroutine to "await" promises.
99
127
*
0 commit comments