[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 namespace React\Promise; 4 5 class Promise implements ExtendedPromiseInterface, CancellablePromiseInterface 6 { 7 private $canceller; 8 private $result; 9 10 private $handlers = []; 11 private $progressHandlers = []; 12 13 private $requiredCancelRequests = 0; 14 private $cancelRequests = 0; 15 16 public function __construct(callable $resolver, callable $canceller = null) 17 { 18 $this->canceller = $canceller; 19 20 // Explicitly overwrite arguments with null values before invoking 21 // resolver function. This ensure that these arguments do not show up 22 // in the stack trace in PHP 7+ only. 23 $cb = $resolver; 24 $resolver = $canceller = null; 25 $this->call($cb); 26 } 27 28 public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) 29 { 30 if (null !== $this->result) { 31 return $this->result->then($onFulfilled, $onRejected, $onProgress); 32 } 33 34 if (null === $this->canceller) { 35 return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); 36 } 37 38 // This promise has a canceller, so we create a new child promise which 39 // has a canceller that invokes the parent canceller if all other 40 // followers are also cancelled. We keep a reference to this promise 41 // instance for the static canceller function and clear this to avoid 42 // keeping a cyclic reference between parent and follower. 43 $parent = $this; 44 ++$parent->requiredCancelRequests; 45 46 return new static( 47 $this->resolver($onFulfilled, $onRejected, $onProgress), 48 static function () use (&$parent) { 49 if (++$parent->cancelRequests >= $parent->requiredCancelRequests) { 50 $parent->cancel(); 51 } 52 53 $parent = null; 54 } 55 ); 56 } 57 58 public function done(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) 59 { 60 if (null !== $this->result) { 61 return $this->result->done($onFulfilled, $onRejected, $onProgress); 62 } 63 64 $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected) { 65 $promise 66 ->done($onFulfilled, $onRejected); 67 }; 68 69 if ($onProgress) { 70 $this->progressHandlers[] = $onProgress; 71 } 72 } 73 74 public function otherwise(callable $onRejected) 75 { 76 return $this->then(null, static function ($reason) use ($onRejected) { 77 if (!_checkTypehint($onRejected, $reason)) { 78 return new RejectedPromise($reason); 79 } 80 81 return $onRejected($reason); 82 }); 83 } 84 85 public function always(callable $onFulfilledOrRejected) 86 { 87 return $this->then(static function ($value) use ($onFulfilledOrRejected) { 88 return resolve($onFulfilledOrRejected())->then(function () use ($value) { 89 return $value; 90 }); 91 }, static function ($reason) use ($onFulfilledOrRejected) { 92 return resolve($onFulfilledOrRejected())->then(function () use ($reason) { 93 return new RejectedPromise($reason); 94 }); 95 }); 96 } 97 98 public function progress(callable $onProgress) 99 { 100 return $this->then(null, null, $onProgress); 101 } 102 103 public function cancel() 104 { 105 if (null === $this->canceller || null !== $this->result) { 106 return; 107 } 108 109 $canceller = $this->canceller; 110 $this->canceller = null; 111 112 $this->call($canceller); 113 } 114 115 private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) 116 { 117 return function ($resolve, $reject, $notify) use ($onFulfilled, $onRejected, $onProgress) { 118 if ($onProgress) { 119 $progressHandler = static function ($update) use ($notify, $onProgress) { 120 try { 121 $notify($onProgress($update)); 122 } catch (\Throwable $e) { 123 $notify($e); 124 } catch (\Exception $e) { 125 $notify($e); 126 } 127 }; 128 } else { 129 $progressHandler = $notify; 130 } 131 132 $this->handlers[] = static function (ExtendedPromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { 133 $promise 134 ->then($onFulfilled, $onRejected) 135 ->done($resolve, $reject, $progressHandler); 136 }; 137 138 $this->progressHandlers[] = $progressHandler; 139 }; 140 } 141 142 private function reject($reason = null) 143 { 144 if (null !== $this->result) { 145 return; 146 } 147 148 $this->settle(reject($reason)); 149 } 150 151 private function settle(ExtendedPromiseInterface $promise) 152 { 153 $promise = $this->unwrap($promise); 154 155 if ($promise === $this) { 156 $promise = new RejectedPromise( 157 new \LogicException('Cannot resolve a promise with itself.') 158 ); 159 } 160 161 $handlers = $this->handlers; 162 163 $this->progressHandlers = $this->handlers = []; 164 $this->result = $promise; 165 $this->canceller = null; 166 167 foreach ($handlers as $handler) { 168 $handler($promise); 169 } 170 } 171 172 private function unwrap($promise) 173 { 174 $promise = $this->extract($promise); 175 176 while ($promise instanceof self && null !== $promise->result) { 177 $promise = $this->extract($promise->result); 178 } 179 180 return $promise; 181 } 182 183 private function extract($promise) 184 { 185 if ($promise instanceof LazyPromise) { 186 $promise = $promise->promise(); 187 } 188 189 return $promise; 190 } 191 192 private function call(callable $cb) 193 { 194 // Explicitly overwrite argument with null value. This ensure that this 195 // argument does not show up in the stack trace in PHP 7+ only. 196 $callback = $cb; 197 $cb = null; 198 199 // Use reflection to inspect number of arguments expected by this callback. 200 // We did some careful benchmarking here: Using reflection to avoid unneeded 201 // function arguments is actually faster than blindly passing them. 202 // Also, this helps avoiding unnecessary function arguments in the call stack 203 // if the callback creates an Exception (creating garbage cycles). 204 if (\is_array($callback)) { 205 $ref = new \ReflectionMethod($callback[0], $callback[1]); 206 } elseif (\is_object($callback) && !$callback instanceof \Closure) { 207 $ref = new \ReflectionMethod($callback, '__invoke'); 208 } else { 209 $ref = new \ReflectionFunction($callback); 210 } 211 $args = $ref->getNumberOfParameters(); 212 213 try { 214 if ($args === 0) { 215 $callback(); 216 } else { 217 // Keep references to this promise instance for the static resolve/reject functions. 218 // By using static callbacks that are not bound to this instance 219 // and passing the target promise instance by reference, we can 220 // still execute its resolving logic and still clear this 221 // reference when settling the promise. This helps avoiding 222 // garbage cycles if any callback creates an Exception. 223 // These assumptions are covered by the test suite, so if you ever feel like 224 // refactoring this, go ahead, any alternative suggestions are welcome! 225 $target =& $this; 226 $progressHandlers =& $this->progressHandlers; 227 228 $callback( 229 static function ($value = null) use (&$target) { 230 if ($target !== null) { 231 $target->settle(resolve($value)); 232 $target = null; 233 } 234 }, 235 static function ($reason = null) use (&$target) { 236 if ($target !== null) { 237 $target->reject($reason); 238 $target = null; 239 } 240 }, 241 static function ($update = null) use (&$progressHandlers) { 242 foreach ($progressHandlers as $handler) { 243 $handler($update); 244 } 245 } 246 ); 247 } 248 } catch (\Throwable $e) { 249 $target = null; 250 $this->reject($e); 251 } catch (\Exception $e) { 252 $target = null; 253 $this->reject($e); 254 } 255 } 256 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |