source: vendor/guzzlehttp/promises/src/Coroutine.php

Last change on this file was e3d4e0a, checked in by Vlado 222039 <vlado.popovski@…>, 7 days ago

Upload project files

  • Property mode set to 100644
File size: 4.1 KB
Line 
1<?php
2
3declare(strict_types=1);
4
5namespace GuzzleHttp\Promise;
6
7use Generator;
8use Throwable;
9
10/**
11 * Creates a promise that is resolved using a generator that yields values or
12 * promises (somewhat similar to C#'s async keyword).
13 *
14 * When called, the Coroutine::of method will start an instance of the generator
15 * and returns a promise that is fulfilled with its final yielded value.
16 *
17 * Control is returned back to the generator when the yielded promise settles.
18 * This can lead to less verbose code when doing lots of sequential async calls
19 * with minimal processing in between.
20 *
21 * use GuzzleHttp\Promise;
22 *
23 * function createPromise($value) {
24 * return new Promise\FulfilledPromise($value);
25 * }
26 *
27 * $promise = Promise\Coroutine::of(function () {
28 * $value = (yield createPromise('a'));
29 * try {
30 * $value = (yield createPromise($value . 'b'));
31 * } catch (\Throwable $e) {
32 * // The promise was rejected.
33 * }
34 * yield $value . 'c';
35 * });
36 *
37 * // Outputs "abc"
38 * $promise->then(function ($v) { echo $v; });
39 *
40 * @param callable $generatorFn Generator function to wrap into a promise.
41 *
42 * @return Promise
43 *
44 * @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
45 */
46final class Coroutine implements PromiseInterface
47{
48 /**
49 * @var PromiseInterface|null
50 */
51 private $currentPromise;
52
53 /**
54 * @var Generator
55 */
56 private $generator;
57
58 /**
59 * @var Promise
60 */
61 private $result;
62
63 public function __construct(callable $generatorFn)
64 {
65 $this->generator = $generatorFn();
66 $this->result = new Promise(function (): void {
67 while (isset($this->currentPromise)) {
68 $this->currentPromise->wait();
69 }
70 });
71 try {
72 $this->nextCoroutine($this->generator->current());
73 } catch (Throwable $throwable) {
74 $this->result->reject($throwable);
75 }
76 }
77
78 /**
79 * Create a new coroutine.
80 */
81 public static function of(callable $generatorFn): self
82 {
83 return new self($generatorFn);
84 }
85
86 public function then(
87 ?callable $onFulfilled = null,
88 ?callable $onRejected = null
89 ): PromiseInterface {
90 return $this->result->then($onFulfilled, $onRejected);
91 }
92
93 public function otherwise(callable $onRejected): PromiseInterface
94 {
95 return $this->result->otherwise($onRejected);
96 }
97
98 public function wait(bool $unwrap = true)
99 {
100 return $this->result->wait($unwrap);
101 }
102
103 public function getState(): string
104 {
105 return $this->result->getState();
106 }
107
108 public function resolve($value): void
109 {
110 $this->result->resolve($value);
111 }
112
113 public function reject($reason): void
114 {
115 $this->result->reject($reason);
116 }
117
118 public function cancel(): void
119 {
120 $this->currentPromise->cancel();
121 $this->result->cancel();
122 }
123
124 private function nextCoroutine($yielded): void
125 {
126 $this->currentPromise = Create::promiseFor($yielded)
127 ->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
128 }
129
130 /**
131 * @internal
132 */
133 public function _handleSuccess($value): void
134 {
135 unset($this->currentPromise);
136 try {
137 $next = $this->generator->send($value);
138 if ($this->generator->valid()) {
139 $this->nextCoroutine($next);
140 } else {
141 $this->result->resolve($value);
142 }
143 } catch (Throwable $throwable) {
144 $this->result->reject($throwable);
145 }
146 }
147
148 /**
149 * @internal
150 */
151 public function _handleFailure($reason): void
152 {
153 unset($this->currentPromise);
154 try {
155 $nextYield = $this->generator->throw(Create::exceptionFor($reason));
156 // The throw was caught, so keep iterating on the coroutine
157 $this->nextCoroutine($nextYield);
158 } catch (Throwable $throwable) {
159 $this->result->reject($throwable);
160 }
161 }
162}
Note: See TracBrowser for help on using the repository browser.