PluginProbe ʕ •ᴥ•ʔ
ShareThis Dashboard for Google Analytics / 3.1.5
ShareThis Dashboard for Google Analytics v3.1.5
3.3.2 trunk 1.0.7 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2.5 2.3.5 2.3.6 2.3.7 2.3.8 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.0.0 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.3.0 3.3.1
googleanalytics / lib / analytics-admin / vendor / guzzlehttp / promises / src / Promise.php
googleanalytics / lib / analytics-admin / vendor / guzzlehttp / promises / src Last commit date
AggregateException.php 3 years ago CancellationException.php 3 years ago Coroutine.php 3 years ago Create.php 3 years ago Each.php 3 years ago EachPromise.php 3 years ago FulfilledPromise.php 3 years ago Is.php 3 years ago Promise.php 3 years ago PromiseInterface.php 3 years ago PromisorInterface.php 3 years ago RejectedPromise.php 3 years ago RejectionException.php 3 years ago TaskQueue.php 3 years ago TaskQueueInterface.php 3 years ago Utils.php 3 years ago functions.php 3 years ago functions_include.php 3 years ago
Promise.php
279 lines
1 <?php
2
3 namespace GuzzleHttp\Promise;
4
5 /**
6 * Promises/A+ implementation that avoids recursion when possible.
7 *
8 * @link https://promisesaplus.com/
9 */
10 class Promise implements PromiseInterface
11 {
12 private $state = self::PENDING;
13 private $result;
14 private $cancelFn;
15 private $waitFn;
16 private $waitList;
17 private $handlers = [];
18
19 /**
20 * @param callable $waitFn Fn that when invoked resolves the promise.
21 * @param callable $cancelFn Fn that when invoked cancels the promise.
22 */
23 public function __construct(
24 callable $waitFn = null,
25 callable $cancelFn = null
26 ) {
27 $this->waitFn = $waitFn;
28 $this->cancelFn = $cancelFn;
29 }
30
31 public function then(
32 callable $onFulfilled = null,
33 callable $onRejected = null
34 ) {
35 if ($this->state === self::PENDING) {
36 $p = new Promise(null, [$this, 'cancel']);
37 $this->handlers[] = [$p, $onFulfilled, $onRejected];
38 $p->waitList = $this->waitList;
39 $p->waitList[] = $this;
40 return $p;
41 }
42
43 // Return a fulfilled promise and immediately invoke any callbacks.
44 if ($this->state === self::FULFILLED) {
45 $promise = Create::promiseFor($this->result);
46 return $onFulfilled ? $promise->then($onFulfilled) : $promise;
47 }
48
49 // It's either cancelled or rejected, so return a rejected promise
50 // and immediately invoke any callbacks.
51 $rejection = Create::rejectionFor($this->result);
52 return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
53 }
54
55 public function otherwise(callable $onRejected)
56 {
57 return $this->then(null, $onRejected);
58 }
59
60 public function wait($unwrap = true)
61 {
62 $this->waitIfPending();
63
64 if ($this->result instanceof PromiseInterface) {
65 return $this->result->wait($unwrap);
66 }
67 if ($unwrap) {
68 if ($this->state === self::FULFILLED) {
69 return $this->result;
70 }
71 // It's rejected so "unwrap" and throw an exception.
72 throw Create::exceptionFor($this->result);
73 }
74 }
75
76 public function getState()
77 {
78 return $this->state;
79 }
80
81 public function cancel()
82 {
83 if ($this->state !== self::PENDING) {
84 return;
85 }
86
87 $this->waitFn = $this->waitList = null;
88
89 if ($this->cancelFn) {
90 $fn = $this->cancelFn;
91 $this->cancelFn = null;
92 try {
93 $fn();
94 } catch (\Throwable $e) {
95 $this->reject($e);
96 } catch (\Exception $e) {
97 $this->reject($e);
98 }
99 }
100
101 // Reject the promise only if it wasn't rejected in a then callback.
102 /** @psalm-suppress RedundantCondition */
103 if ($this->state === self::PENDING) {
104 $this->reject(new CancellationException('Promise has been cancelled'));
105 }
106 }
107
108 public function resolve($value)
109 {
110 $this->settle(self::FULFILLED, $value);
111 }
112
113 public function reject($reason)
114 {
115 $this->settle(self::REJECTED, $reason);
116 }
117
118 private function settle($state, $value)
119 {
120 if ($this->state !== self::PENDING) {
121 // Ignore calls with the same resolution.
122 if ($state === $this->state && $value === $this->result) {
123 return;
124 }
125 throw $this->state === $state
126 ? new \LogicException("The promise is already {$state}.")
127 : new \LogicException("Cannot change a {$this->state} promise to {$state}");
128 }
129
130 if ($value === $this) {
131 throw new \LogicException('Cannot fulfill or reject a promise with itself');
132 }
133
134 // Clear out the state of the promise but stash the handlers.
135 $this->state = $state;
136 $this->result = $value;
137 $handlers = $this->handlers;
138 $this->handlers = null;
139 $this->waitList = $this->waitFn = null;
140 $this->cancelFn = null;
141
142 if (!$handlers) {
143 return;
144 }
145
146 // If the value was not a settled promise or a thenable, then resolve
147 // it in the task queue using the correct ID.
148 if (!is_object($value) || !method_exists($value, 'then')) {
149 $id = $state === self::FULFILLED ? 1 : 2;
150 // It's a success, so resolve the handlers in the queue.
151 Utils::queue()->add(static function () use ($id, $value, $handlers) {
152 foreach ($handlers as $handler) {
153 self::callHandler($id, $value, $handler);
154 }
155 });
156 } elseif ($value instanceof Promise && Is::pending($value)) {
157 // We can just merge our handlers onto the next promise.
158 $value->handlers = array_merge($value->handlers, $handlers);
159 } else {
160 // Resolve the handlers when the forwarded promise is resolved.
161 $value->then(
162 static function ($value) use ($handlers) {
163 foreach ($handlers as $handler) {
164 self::callHandler(1, $value, $handler);
165 }
166 },
167 static function ($reason) use ($handlers) {
168 foreach ($handlers as $handler) {
169 self::callHandler(2, $reason, $handler);
170 }
171 }
172 );
173 }
174 }
175
176 /**
177 * Call a stack of handlers using a specific callback index and value.
178 *
179 * @param int $index 1 (resolve) or 2 (reject).
180 * @param mixed $value Value to pass to the callback.
181 * @param array $handler Array of handler data (promise and callbacks).
182 */
183 private static function callHandler($index, $value, array $handler)
184 {
185 /** @var PromiseInterface $promise */
186 $promise = $handler[0];
187
188 // The promise may have been cancelled or resolved before placing
189 // this thunk in the queue.
190 if (Is::settled($promise)) {
191 return;
192 }
193
194 try {
195 if (isset($handler[$index])) {
196 /*
197 * If $f throws an exception, then $handler will be in the exception
198 * stack trace. Since $handler contains a reference to the callable
199 * itself we get a circular reference. We clear the $handler
200 * here to avoid that memory leak.
201 */
202 $f = $handler[$index];
203 unset($handler);
204 $promise->resolve($f($value));
205 } elseif ($index === 1) {
206 // Forward resolution values as-is.
207 $promise->resolve($value);
208 } else {
209 // Forward rejections down the chain.
210 $promise->reject($value);
211 }
212 } catch (\Throwable $reason) {
213 $promise->reject($reason);
214 } catch (\Exception $reason) {
215 $promise->reject($reason);
216 }
217 }
218
219 private function waitIfPending()
220 {
221 if ($this->state !== self::PENDING) {
222 return;
223 } elseif ($this->waitFn) {
224 $this->invokeWaitFn();
225 } elseif ($this->waitList) {
226 $this->invokeWaitList();
227 } else {
228 // If there's no wait function, then reject the promise.
229 $this->reject('Cannot wait on a promise that has '
230 . 'no internal wait function. You must provide a wait '
231 . 'function when constructing the promise to be able to '
232 . 'wait on a promise.');
233 }
234
235 Utils::queue()->run();
236
237 /** @psalm-suppress RedundantCondition */
238 if ($this->state === self::PENDING) {
239 $this->reject('Invoking the wait callback did not resolve the promise');
240 }
241 }
242
243 private function invokeWaitFn()
244 {
245 try {
246 $wfn = $this->waitFn;
247 $this->waitFn = null;
248 $wfn(true);
249 } catch (\Exception $reason) {
250 if ($this->state === self::PENDING) {
251 // The promise has not been resolved yet, so reject the promise
252 // with the exception.
253 $this->reject($reason);
254 } else {
255 // The promise was already resolved, so there's a problem in
256 // the application.
257 throw $reason;
258 }
259 }
260 }
261
262 private function invokeWaitList()
263 {
264 $waitList = $this->waitList;
265 $this->waitList = null;
266
267 foreach ($waitList as $result) {
268 do {
269 $result->waitIfPending();
270 $result = $result->result;
271 } while ($result instanceof Promise);
272
273 if ($result instanceof PromiseInterface) {
274 $result->wait(false);
275 }
276 }
277 }
278 }
279