···11+# Changelog
22+33+## 4.3.0 (2024-06-04)
44+55+* Feature: Improve performance by avoiding unneeded references in `FiberMap`.
66+ (#88 by @clue)
77+88+* Feature: Improve PHP 8.4+ support by avoiding implicitly nullable type declarations.
99+ (#87 by @clue)
1010+1111+* Improve type safety for test environment.
1212+ (#86 by @SimonFrings)
1313+1414+## 4.2.0 (2023-11-22)
1515+1616+* Feature: Add Promise v3 template types for all public functions.
1717+ (#40 by @WyriHaximus and @clue)
1818+1919+ All our public APIs now use Promise v3 template types to guide IDEs and static
2020+ analysis tools (like PHPStan), helping with proper type usage and improving
2121+ code quality:
2222+2323+ ```php
2424+ assertType('bool', await(resolve(true)));
2525+ assertType('PromiseInterface<bool>', async(fn(): bool => true)());
2626+ assertType('PromiseInterface<bool>', coroutine(fn(): bool => true));
2727+ ```
2828+2929+* Feature: Full PHP 8.3 compatibility.
3030+ (#81 by @clue)
3131+3232+* Update test suite to avoid unhandled promise rejections.
3333+ (#79 by @clue)
3434+3535+## 4.1.0 (2023-06-22)
3636+3737+* Feature: Add new `delay()` function to delay program execution.
3838+ (#69 and #78 by @clue)
3939+4040+ ```php
4141+ echo 'a';
4242+ Loop::addTimer(1.0, function () {
4343+ echo 'b';
4444+ });
4545+ React\Async\delay(3.0);
4646+ echo 'c';
4747+4848+ // prints "a" at t=0.0s
4949+ // prints "b" at t=1.0s
5050+ // prints "c" at t=3.0s
5151+ ```
5252+5353+* Update test suite, add PHPStan with `max` level and report failed assertions.
5454+ (#66 and #76 by @clue and #61 and #73 by @WyriHaximus)
5555+5656+## 4.0.0 (2022-07-11)
5757+5858+A major new feature release, see [**release announcement**](https://clue.engineering/2022/announcing-reactphp-async).
5959+6060+* We'd like to emphasize that this component is production ready and battle-tested.
6161+ We plan to support all long-term support (LTS) releases for at least 24 months,
6262+ so you have a rock-solid foundation to build on top of.
6363+6464+* The v4 release will be the way forward for this package. However, we will still
6565+ actively support v3 and v2 to provide a smooth upgrade path for those not yet
6666+ on PHP 8.1+. If you're using an older PHP version, you may use either version
6767+ which all provide a compatible API but may not take advantage of newer language
6868+ features. You may target multiple versions at the same time to support a wider range of
6969+ PHP versions:
7070+7171+ * [`4.x` branch](https://github.com/reactphp/async/tree/4.x) (PHP 8.1+)
7272+ * [`3.x` branch](https://github.com/reactphp/async/tree/3.x) (PHP 7.1+)
7373+ * [`2.x` branch](https://github.com/reactphp/async/tree/2.x) (PHP 5.3+)
7474+7575+This update involves some major new features and a minor BC break over the
7676+`v3.0.0` release. We've tried hard to avoid BC breaks where possible and
7777+minimize impact otherwise. We expect that most consumers of this package will be
7878+affected by BC breaks, but updating should take no longer than a few minutes.
7979+See below for more details:
8080+8181+* Feature / BC break: Require PHP 8.1+ and add `mixed` type declarations.
8282+ (#14 by @clue)
8383+8484+* Feature: Add Fiber-based `async()` and `await()` functions.
8585+ (#15, #18, #19 and #20 by @WyriHaximus and #26, #28, #30, #32, #34, #55 and #57 by @clue)
8686+8787+* Project maintenance, rename `main` branch to `4.x` and update installation instructions.
8888+ (#29 by @clue)
8989+9090+The following changes had to be ported to this release due to our branching
9191+strategy, but also appeared in the `v3.0.0` release:
9292+9393+* Feature: Support iterable type for `parallel()` + `series()` + `waterfall()`.
9494+ (#49 by @clue)
9595+9696+* Feature: Forward compatibility with upcoming Promise v3.
9797+ (#48 by @clue)
9898+9999+* Minor documentation improvements.
100100+ (#36 by @SimonFrings and #51 by @nhedger)
101101+102102+## 3.0.0 (2022-07-11)
103103+104104+See [`3.x` CHANGELOG](https://github.com/reactphp/async/blob/3.x/CHANGELOG.md) for more details.
105105+106106+## 2.0.0 (2022-07-11)
107107+108108+See [`2.x` CHANGELOG](https://github.com/reactphp/async/blob/2.x/CHANGELOG.md) for more details.
109109+110110+## 1.0.0 (2013-02-07)
111111+112112+* First tagged release
+19
vendor/react/async/LICENSE
···11+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
22+33+Permission is hereby granted, free of charge, to any person obtaining a copy
44+of this software and associated documentation files (the "Software"), to deal
55+in the Software without restriction, including without limitation the rights
66+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
77+copies of the Software, and to permit persons to whom the Software is furnished
88+to do so, subject to the following conditions:
99+1010+The above copyright notice and this permission notice shall be included in all
1111+copies or substantial portions of the Software.
1212+1313+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1414+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1515+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1616+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1717+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1818+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1919+THE SOFTWARE.
+672
vendor/react/async/README.md
···11+# Async Utilities
22+33+[](https://github.com/reactphp/async/actions)
44+[](https://packagist.org/packages/react/async)
55+66+Async utilities and fibers for [ReactPHP](https://reactphp.org/).
77+88+This library allows you to manage async control flow. It provides a number of
99+combinators for [Promise](https://github.com/reactphp/promise)-based APIs.
1010+Instead of nesting or chaining promise callbacks, you can declare them as a
1111+list, which is resolved sequentially in an async manner.
1212+React/Async will not automagically change blocking code to be async. You need
1313+to have an actual event loop and non-blocking libraries interacting with that
1414+event loop for it to work. As long as you have a Promise-based API that runs in
1515+an event loop, it can be used with this library.
1616+1717+**Table of Contents**
1818+1919+* [Usage](#usage)
2020+ * [async()](#async)
2121+ * [await()](#await)
2222+ * [coroutine()](#coroutine)
2323+ * [delay()](#delay)
2424+ * [parallel()](#parallel)
2525+ * [series()](#series)
2626+ * [waterfall()](#waterfall)
2727+* [Todo](#todo)
2828+* [Install](#install)
2929+* [Tests](#tests)
3030+* [License](#license)
3131+3232+## Usage
3333+3434+This lightweight library consists only of a few simple functions.
3535+All functions reside under the `React\Async` namespace.
3636+3737+The below examples refer to all functions with their fully-qualified names like this:
3838+3939+```php
4040+React\Async\await(…);
4141+```
4242+4343+As of PHP 5.6+ you can also import each required function into your code like this:
4444+4545+```php
4646+use function React\Async\await;
4747+4848+await(…);
4949+```
5050+5151+Alternatively, you can also use an import statement similar to this:
5252+5353+```php
5454+use React\Async;
5555+5656+Async\await(…);
5757+```
5858+5959+### async()
6060+6161+The `async(callable():(PromiseInterface<T>|T) $function): (callable():PromiseInterface<T>)` function can be used to
6262+return an async function for a function that uses [`await()`](#await) internally.
6363+6464+This function is specifically designed to complement the [`await()` function](#await).
6565+The [`await()` function](#await) can be considered *blocking* from the
6666+perspective of the calling code. You can avoid this blocking behavior by
6767+wrapping it in an `async()` function call. Everything inside this function
6868+will still be blocked, but everything outside this function can be executed
6969+asynchronously without blocking:
7070+7171+```php
7272+Loop::addTimer(0.5, React\Async\async(function () {
7373+ echo 'a';
7474+ React\Async\await(React\Promise\Timer\sleep(1.0));
7575+ echo 'c';
7676+}));
7777+7878+Loop::addTimer(1.0, function () {
7979+ echo 'b';
8080+});
8181+8282+// prints "a" at t=0.5s
8383+// prints "b" at t=1.0s
8484+// prints "c" at t=1.5s
8585+```
8686+8787+See also the [`await()` function](#await) for more details.
8888+8989+Note that this function only works in tandem with the [`await()` function](#await).
9090+In particular, this function does not "magically" make any blocking function
9191+non-blocking:
9292+9393+```php
9494+Loop::addTimer(0.5, React\Async\async(function () {
9595+ echo 'a';
9696+ sleep(1); // broken: using PHP's blocking sleep() for demonstration purposes
9797+ echo 'c';
9898+}));
9999+100100+Loop::addTimer(1.0, function () {
101101+ echo 'b';
102102+});
103103+104104+// prints "a" at t=0.5s
105105+// prints "c" at t=1.5s: Correct timing, but wrong order
106106+// prints "b" at t=1.5s: Triggered too late because it was blocked
107107+```
108108+109109+As an alternative, you should always make sure to use this function in tandem
110110+with the [`await()` function](#await) and an async API returning a promise
111111+as shown in the previous example.
112112+113113+The `async()` function is specifically designed for cases where it is used
114114+as a callback (such as an event loop timer, event listener, or promise
115115+callback). For this reason, it returns a new function wrapping the given
116116+`$function` instead of directly invoking it and returning its value.
117117+118118+```php
119119+use function React\Async\async;
120120+121121+Loop::addTimer(1.0, async(function () { … }));
122122+$connection->on('close', async(function () { … }));
123123+$stream->on('data', async(function ($data) { … }));
124124+$promise->then(async(function (int $result) { … }));
125125+```
126126+127127+You can invoke this wrapping function to invoke the given `$function` with
128128+any arguments given as-is. The function will always return a Promise which
129129+will be fulfilled with whatever your `$function` returns. Likewise, it will
130130+return a promise that will be rejected if you throw an `Exception` or
131131+`Throwable` from your `$function`. This allows you to easily create
132132+Promise-based functions:
133133+134134+```php
135135+$promise = React\Async\async(function (): int {
136136+ $browser = new React\Http\Browser();
137137+ $urls = [
138138+ 'https://example.com/alice',
139139+ 'https://example.com/bob'
140140+ ];
141141+142142+ $bytes = 0;
143143+ foreach ($urls as $url) {
144144+ $response = React\Async\await($browser->get($url));
145145+ assert($response instanceof Psr\Http\Message\ResponseInterface);
146146+ $bytes += $response->getBody()->getSize();
147147+ }
148148+ return $bytes;
149149+})();
150150+151151+$promise->then(function (int $bytes) {
152152+ echo 'Total size: ' . $bytes . PHP_EOL;
153153+}, function (Exception $e) {
154154+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
155155+});
156156+```
157157+158158+The previous example uses [`await()`](#await) inside a loop to highlight how
159159+this vastly simplifies consuming asynchronous operations. At the same time,
160160+this naive example does not leverage concurrent execution, as it will
161161+essentially "await" between each operation. In order to take advantage of
162162+concurrent execution within the given `$function`, you can "await" multiple
163163+promises by using a single [`await()`](#await) together with Promise-based
164164+primitives like this:
165165+166166+```php
167167+$promise = React\Async\async(function (): int {
168168+ $browser = new React\Http\Browser();
169169+ $urls = [
170170+ 'https://example.com/alice',
171171+ 'https://example.com/bob'
172172+ ];
173173+174174+ $promises = [];
175175+ foreach ($urls as $url) {
176176+ $promises[] = $browser->get($url);
177177+ }
178178+179179+ try {
180180+ $responses = React\Async\await(React\Promise\all($promises));
181181+ } catch (Exception $e) {
182182+ foreach ($promises as $promise) {
183183+ $promise->cancel();
184184+ }
185185+ throw $e;
186186+ }
187187+188188+ $bytes = 0;
189189+ foreach ($responses as $response) {
190190+ assert($response instanceof Psr\Http\Message\ResponseInterface);
191191+ $bytes += $response->getBody()->getSize();
192192+ }
193193+ return $bytes;
194194+})();
195195+196196+$promise->then(function (int $bytes) {
197197+ echo 'Total size: ' . $bytes . PHP_EOL;
198198+}, function (Exception $e) {
199199+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
200200+});
201201+```
202202+203203+The returned promise is implemented in such a way that it can be cancelled
204204+when it is still pending. Cancelling a pending promise will cancel any awaited
205205+promises inside that fiber or any nested fibers. As such, the following example
206206+will only output `ab` and cancel the pending [`delay()`](#delay).
207207+The [`await()`](#await) calls in this example would throw a `RuntimeException`
208208+from the cancelled [`delay()`](#delay) call that bubbles up through the fibers.
209209+210210+```php
211211+$promise = async(static function (): int {
212212+ echo 'a';
213213+ await(async(static function (): void {
214214+ echo 'b';
215215+ delay(2);
216216+ echo 'c';
217217+ })());
218218+ echo 'd';
219219+220220+ return time();
221221+})();
222222+223223+$promise->cancel();
224224+await($promise);
225225+```
226226+227227+### await()
228228+229229+The `await(PromiseInterface<T> $promise): T` function can be used to
230230+block waiting for the given `$promise` to be fulfilled.
231231+232232+```php
233233+$result = React\Async\await($promise);
234234+```
235235+236236+This function will only return after the given `$promise` has settled, i.e.
237237+either fulfilled or rejected. While the promise is pending, this function
238238+can be considered *blocking* from the perspective of the calling code.
239239+You can avoid this blocking behavior by wrapping it in an [`async()` function](#async)
240240+call. Everything inside this function will still be blocked, but everything
241241+outside this function can be executed asynchronously without blocking:
242242+243243+```php
244244+Loop::addTimer(0.5, React\Async\async(function () {
245245+ echo 'a';
246246+ React\Async\await(React\Promise\Timer\sleep(1.0));
247247+ echo 'c';
248248+}));
249249+250250+Loop::addTimer(1.0, function () {
251251+ echo 'b';
252252+});
253253+254254+// prints "a" at t=0.5s
255255+// prints "b" at t=1.0s
256256+// prints "c" at t=1.5s
257257+```
258258+259259+See also the [`async()` function](#async) for more details.
260260+261261+Once the promise is fulfilled, this function will return whatever the promise
262262+resolved to.
263263+264264+Once the promise is rejected, this will throw whatever the promise rejected
265265+with. If the promise did not reject with an `Exception` or `Throwable`, then
266266+this function will throw an `UnexpectedValueException` instead.
267267+268268+```php
269269+try {
270270+ $result = React\Async\await($promise);
271271+ // promise successfully fulfilled with $result
272272+ echo 'Result: ' . $result;
273273+} catch (Throwable $e) {
274274+ // promise rejected with $e
275275+ echo 'Error: ' . $e->getMessage();
276276+}
277277+```
278278+279279+### coroutine()
280280+281281+The `coroutine(callable(mixed ...$args):(\Generator|PromiseInterface<T>|T) $function, mixed ...$args): PromiseInterface<T>` function can be used to
282282+execute a Generator-based coroutine to "await" promises.
283283+284284+```php
285285+React\Async\coroutine(function () {
286286+ $browser = new React\Http\Browser();
287287+288288+ try {
289289+ $response = yield $browser->get('https://example.com/');
290290+ assert($response instanceof Psr\Http\Message\ResponseInterface);
291291+ echo $response->getBody();
292292+ } catch (Exception $e) {
293293+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
294294+ }
295295+});
296296+```
297297+298298+Using Generator-based coroutines is an alternative to directly using the
299299+underlying promise APIs. For many use cases, this makes using promise-based
300300+APIs much simpler, as it resembles a synchronous code flow more closely.
301301+The above example performs the equivalent of directly using the promise APIs:
302302+303303+```php
304304+$browser = new React\Http\Browser();
305305+306306+$browser->get('https://example.com/')->then(function (Psr\Http\Message\ResponseInterface $response) {
307307+ echo $response->getBody();
308308+}, function (Exception $e) {
309309+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
310310+});
311311+```
312312+313313+The `yield` keyword can be used to "await" a promise resolution. Internally,
314314+it will turn the entire given `$function` into a [`Generator`](https://www.php.net/manual/en/class.generator.php).
315315+This allows the execution to be interrupted and resumed at the same place
316316+when the promise is fulfilled. The `yield` statement returns whatever the
317317+promise is fulfilled with. If the promise is rejected, it will throw an
318318+`Exception` or `Throwable`.
319319+320320+The `coroutine()` function will always return a Promise which will be
321321+fulfilled with whatever your `$function` returns. Likewise, it will return
322322+a promise that will be rejected if you throw an `Exception` or `Throwable`
323323+from your `$function`. This allows you to easily create Promise-based
324324+functions:
325325+326326+```php
327327+$promise = React\Async\coroutine(function () {
328328+ $browser = new React\Http\Browser();
329329+ $urls = [
330330+ 'https://example.com/alice',
331331+ 'https://example.com/bob'
332332+ ];
333333+334334+ $bytes = 0;
335335+ foreach ($urls as $url) {
336336+ $response = yield $browser->get($url);
337337+ assert($response instanceof Psr\Http\Message\ResponseInterface);
338338+ $bytes += $response->getBody()->getSize();
339339+ }
340340+ return $bytes;
341341+});
342342+343343+$promise->then(function (int $bytes) {
344344+ echo 'Total size: ' . $bytes . PHP_EOL;
345345+}, function (Exception $e) {
346346+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
347347+});
348348+```
349349+350350+The previous example uses a `yield` statement inside a loop to highlight how
351351+this vastly simplifies consuming asynchronous operations. At the same time,
352352+this naive example does not leverage concurrent execution, as it will
353353+essentially "await" between each operation. In order to take advantage of
354354+concurrent execution within the given `$function`, you can "await" multiple
355355+promises by using a single `yield` together with Promise-based primitives
356356+like this:
357357+358358+```php
359359+$promise = React\Async\coroutine(function () {
360360+ $browser = new React\Http\Browser();
361361+ $urls = [
362362+ 'https://example.com/alice',
363363+ 'https://example.com/bob'
364364+ ];
365365+366366+ $promises = [];
367367+ foreach ($urls as $url) {
368368+ $promises[] = $browser->get($url);
369369+ }
370370+371371+ try {
372372+ $responses = yield React\Promise\all($promises);
373373+ } catch (Exception $e) {
374374+ foreach ($promises as $promise) {
375375+ $promise->cancel();
376376+ }
377377+ throw $e;
378378+ }
379379+380380+ $bytes = 0;
381381+ foreach ($responses as $response) {
382382+ assert($response instanceof Psr\Http\Message\ResponseInterface);
383383+ $bytes += $response->getBody()->getSize();
384384+ }
385385+ return $bytes;
386386+});
387387+388388+$promise->then(function (int $bytes) {
389389+ echo 'Total size: ' . $bytes . PHP_EOL;
390390+}, function (Exception $e) {
391391+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
392392+});
393393+```
394394+395395+### delay()
396396+397397+The `delay(float $seconds): void` function can be used to
398398+delay program execution for duration given in `$seconds`.
399399+400400+```php
401401+React\Async\delay($seconds);
402402+```
403403+404404+This function will only return after the given number of `$seconds` have
405405+elapsed. If there are no other events attached to this loop, it will behave
406406+similar to PHP's [`sleep()` function](https://www.php.net/manual/en/function.sleep.php).
407407+408408+```php
409409+echo 'a';
410410+React\Async\delay(1.0);
411411+echo 'b';
412412+413413+// prints "a" at t=0.0s
414414+// prints "b" at t=1.0s
415415+```
416416+417417+Unlike PHP's [`sleep()` function](https://www.php.net/manual/en/function.sleep.php),
418418+this function may not necessarily halt execution of the entire process thread.
419419+Instead, it allows the event loop to run any other events attached to the
420420+same loop until the delay returns:
421421+422422+```php
423423+echo 'a';
424424+Loop::addTimer(1.0, function (): void {
425425+ echo 'b';
426426+});
427427+React\Async\delay(3.0);
428428+echo 'c';
429429+430430+// prints "a" at t=0.0s
431431+// prints "b" at t=1.0s
432432+// prints "c" at t=3.0s
433433+```
434434+435435+This behavior is especially useful if you want to delay the program execution
436436+of a particular routine, such as when building a simple polling or retry
437437+mechanism:
438438+439439+```php
440440+try {
441441+ something();
442442+} catch (Throwable) {
443443+ // in case of error, retry after a short delay
444444+ React\Async\delay(1.0);
445445+ something();
446446+}
447447+```
448448+449449+Because this function only returns after some time has passed, it can be
450450+considered *blocking* from the perspective of the calling code. You can avoid
451451+this blocking behavior by wrapping it in an [`async()` function](#async) call.
452452+Everything inside this function will still be blocked, but everything outside
453453+this function can be executed asynchronously without blocking:
454454+455455+```php
456456+Loop::addTimer(0.5, React\Async\async(function (): void {
457457+ echo 'a';
458458+ React\Async\delay(1.0);
459459+ echo 'c';
460460+}));
461461+462462+Loop::addTimer(1.0, function (): void {
463463+ echo 'b';
464464+});
465465+466466+// prints "a" at t=0.5s
467467+// prints "b" at t=1.0s
468468+// prints "c" at t=1.5s
469469+```
470470+471471+See also the [`async()` function](#async) for more details.
472472+473473+Internally, the `$seconds` argument will be used as a timer for the loop so that
474474+it keeps running until this timer triggers. This implies that if you pass a
475475+really small (or negative) value, it will still start a timer and will thus
476476+trigger at the earliest possible time in the future.
477477+478478+The function is implemented in such a way that it can be cancelled when it is
479479+running inside an [`async()` function](#async). Cancelling the resulting
480480+promise will clean up any pending timers and throw a `RuntimeException` from
481481+the pending delay which in turn would reject the resulting promise.
482482+483483+```php
484484+$promise = async(function (): void {
485485+ echo 'a';
486486+ delay(3.0);
487487+ echo 'b';
488488+})();
489489+490490+Loop::addTimer(2.0, function () use ($promise): void {
491491+ $promise->cancel();
492492+});
493493+494494+// prints "a" at t=0.0s
495495+// rejects $promise at t=2.0
496496+// never prints "b"
497497+```
498498+499499+### parallel()
500500+501501+The `parallel(iterable<callable():PromiseInterface<T>> $tasks): PromiseInterface<array<T>>` function can be used
502502+like this:
503503+504504+```php
505505+<?php
506506+507507+use React\EventLoop\Loop;
508508+use React\Promise\Promise;
509509+510510+React\Async\parallel([
511511+ function () {
512512+ return new Promise(function ($resolve) {
513513+ Loop::addTimer(1, function () use ($resolve) {
514514+ $resolve('Slept for a whole second');
515515+ });
516516+ });
517517+ },
518518+ function () {
519519+ return new Promise(function ($resolve) {
520520+ Loop::addTimer(1, function () use ($resolve) {
521521+ $resolve('Slept for another whole second');
522522+ });
523523+ });
524524+ },
525525+ function () {
526526+ return new Promise(function ($resolve) {
527527+ Loop::addTimer(1, function () use ($resolve) {
528528+ $resolve('Slept for yet another whole second');
529529+ });
530530+ });
531531+ },
532532+])->then(function (array $results) {
533533+ foreach ($results as $result) {
534534+ var_dump($result);
535535+ }
536536+}, function (Exception $e) {
537537+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
538538+});
539539+```
540540+541541+### series()
542542+543543+The `series(iterable<callable():PromiseInterface<T>> $tasks): PromiseInterface<array<T>>` function can be used
544544+like this:
545545+546546+```php
547547+<?php
548548+549549+use React\EventLoop\Loop;
550550+use React\Promise\Promise;
551551+552552+React\Async\series([
553553+ function () {
554554+ return new Promise(function ($resolve) {
555555+ Loop::addTimer(1, function () use ($resolve) {
556556+ $resolve('Slept for a whole second');
557557+ });
558558+ });
559559+ },
560560+ function () {
561561+ return new Promise(function ($resolve) {
562562+ Loop::addTimer(1, function () use ($resolve) {
563563+ $resolve('Slept for another whole second');
564564+ });
565565+ });
566566+ },
567567+ function () {
568568+ return new Promise(function ($resolve) {
569569+ Loop::addTimer(1, function () use ($resolve) {
570570+ $resolve('Slept for yet another whole second');
571571+ });
572572+ });
573573+ },
574574+])->then(function (array $results) {
575575+ foreach ($results as $result) {
576576+ var_dump($result);
577577+ }
578578+}, function (Exception $e) {
579579+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
580580+});
581581+```
582582+583583+### waterfall()
584584+585585+The `waterfall(iterable<callable(mixed=):PromiseInterface<T>> $tasks): PromiseInterface<T>` function can be used
586586+like this:
587587+588588+```php
589589+<?php
590590+591591+use React\EventLoop\Loop;
592592+use React\Promise\Promise;
593593+594594+$addOne = function ($prev = 0) {
595595+ return new Promise(function ($resolve) use ($prev) {
596596+ Loop::addTimer(1, function () use ($prev, $resolve) {
597597+ $resolve($prev + 1);
598598+ });
599599+ });
600600+};
601601+602602+React\Async\waterfall([
603603+ $addOne,
604604+ $addOne,
605605+ $addOne
606606+])->then(function ($prev) {
607607+ echo "Final result is $prev\n";
608608+}, function (Exception $e) {
609609+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
610610+});
611611+```
612612+613613+## Todo
614614+615615+ * Implement queue()
616616+617617+## Install
618618+619619+The recommended way to install this library is [through Composer](https://getcomposer.org/).
620620+[New to Composer?](https://getcomposer.org/doc/00-intro.md)
621621+622622+This project follows [SemVer](https://semver.org/).
623623+This will install the latest supported version from this branch:
624624+625625+```bash
626626+composer require react/async:^4.3
627627+```
628628+629629+See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
630630+631631+This project aims to run on any platform and thus does not require any PHP
632632+extensions and supports running on PHP 8.1+.
633633+It's *highly recommended to use the latest supported PHP version* for this project.
634634+635635+We're committed to providing long-term support (LTS) options and to provide a
636636+smooth upgrade path. If you're using an older PHP version, you may use the
637637+[`3.x` branch](https://github.com/reactphp/async/tree/3.x) (PHP 7.1+) or
638638+[`2.x` branch](https://github.com/reactphp/async/tree/2.x) (PHP 5.3+) which both
639639+provide a compatible API but do not take advantage of newer language features.
640640+You may target multiple versions at the same time to support a wider range of
641641+PHP versions like this:
642642+643643+```bash
644644+composer require "react/async:^4 || ^3 || ^2"
645645+```
646646+647647+## Tests
648648+649649+To run the test suite, you first need to clone this repo and then install all
650650+dependencies [through Composer](https://getcomposer.org/):
651651+652652+```bash
653653+composer install
654654+```
655655+656656+To run the test suite, go to the project root and run:
657657+658658+```bash
659659+vendor/bin/phpunit
660660+```
661661+662662+On top of this, we use PHPStan on max level to ensure type safety across the project:
663663+664664+```bash
665665+vendor/bin/phpstan
666666+```
667667+668668+## License
669669+670670+MIT, see [LICENSE file](LICENSE).
671671+672672+This project is heavily influenced by [async.js](https://github.com/caolan/async).
···11+<?php
22+33+namespace React\Async;
44+55+/**
66+ * This factory its only purpose is interoperability. Where with
77+ * event loops one could simply wrap another event loop. But with fibers
88+ * that has become impossible and as such we provide this factory and the
99+ * FiberInterface.
1010+ *
1111+ * Usage is not documented and as such not supported and might chang without
1212+ * notice. Use at your own risk.
1313+ *
1414+ * @internal
1515+ */
1616+final class FiberFactory
1717+{
1818+ private static ?\Closure $factory = null;
1919+2020+ public static function create(): FiberInterface
2121+ {
2222+ return (self::factory())();
2323+ }
2424+2525+ public static function factory(?\Closure $factory = null): \Closure
2626+ {
2727+ if ($factory !== null) {
2828+ self::$factory = $factory;
2929+ }
3030+3131+ return self::$factory ?? static fn (): FiberInterface => new SimpleFiber();
3232+ }
3333+}
+23
vendor/react/async/src/FiberInterface.php
···11+<?php
22+33+namespace React\Async;
44+55+/**
66+ * This interface its only purpose is interoperability. Where with
77+ * event loops one could simply wrap another event loop. But with fibers
88+ * that has become impossible and as such we provide this interface and the
99+ * FiberFactory.
1010+ *
1111+ * Usage is not documented and as such not supported and might chang without
1212+ * notice. Use at your own risk.
1313+ *
1414+ * @internal
1515+ */
1616+interface FiberInterface
1717+{
1818+ public function resume(mixed $value): void;
1919+2020+ public function throw(\Throwable $throwable): void;
2121+2222+ public function suspend(): mixed;
2323+}
···11+# Changelog
22+33+## 1.5.0 (2023-11-13)
44+55+* Feature: Improve performance by using `spl_object_id()` on PHP 7.2+.
66+ (#267 by @samsonasik)
77+88+* Feature: Full PHP 8.3 compatibility.
99+ (#269 by @clue)
1010+1111+* Update tests for `ext-uv` on PHP 8+ and legacy PHP.
1212+ (#270 by @clue and #268 by @SimonFrings)
1313+1414+## 1.4.0 (2023-05-05)
1515+1616+* Feature: Improve performance of `Loop` by avoiding unneeded method calls.
1717+ (#266 by @clue)
1818+1919+* Feature: Support checking `EINTR` constant from `ext-pcntl` without `ext-sockets`.
2020+ (#265 by @clue)
2121+2222+* Minor documentation improvements.
2323+ (#254 by @nhedger)
2424+2525+* Improve test suite, run tests on PHP 8.2 and report failed assertions.
2626+ (#258 by @WyriHaximus, #264 by @clue and #251, #261 and #262 by @SimonFrings)
2727+2828+## 1.3.0 (2022-03-17)
2929+3030+* Feature: Improve default `StreamSelectLoop` to report any warnings for invalid streams.
3131+ (#245 by @clue)
3232+3333+* Feature: Improve performance of `StreamSelectLoop` when no timers are scheduled.
3434+ (#246 by @clue)
3535+3636+* Fix: Fix periodic timer with zero interval for `ExtEvLoop` and legacy `ExtLibevLoop`.
3737+ (#243 by @lucasnetau)
3838+3939+* Minor documentation improvements, update PHP version references.
4040+ (#240, #248 and #250 by @SimonFrings, #241 by @dbu and #249 by @clue)
4141+4242+* Improve test suite and test against PHP 8.1.
4343+ (#238 by @WyriHaximus and #242 by @clue)
4444+4545+## 1.2.0 (2021-07-11)
4646+4747+A major new feature release, see [**release announcement**](https://clue.engineering/2021/announcing-reactphp-default-loop).
4848+4949+* Feature: Introduce new concept of default loop with the new `Loop` class.
5050+ (#226 by @WyriHaximus, #229, #231 and #232 by @clue)
5151+5252+ The `Loop` class exists as a convenient global accessor for the event loop.
5353+ It provides all methods that exist on the `LoopInterface` as static methods and
5454+ will automatically execute the loop at the end of the program:
5555+5656+ ```php
5757+ $timer = Loop::addPeriodicTimer(0.1, function () {
5858+ echo 'Tick' . PHP_EOL;
5959+ });
6060+6161+ Loop::addTimer(1.0, function () use ($timer) {
6262+ Loop::cancelTimer($timer);
6363+ echo 'Done' . PHP_EOL;
6464+ });
6565+ ```
6666+6767+ The explicit loop instructions are still valid and may still be useful in some applications,
6868+ especially for a transition period towards the more concise style.
6969+ The `Loop::get()` method can be used to get the currently active event loop instance.
7070+7171+ ```php
7272+ // deprecated
7373+ $loop = React\EventLoop\Factory::create();
7474+7575+ // new
7676+ $loop = React\EventLoop\Loop::get();
7777+ ```
7878+7979+* Minor documentation improvements and mark legacy extensions as deprecated.
8080+ (#234 by @SimonFrings, #214 by @WyriHaximus and #233 and #235 by @nhedger)
8181+8282+* Improve test suite, use GitHub actions for continuous integration (CI),
8383+ update PHPUnit config and run tests on PHP 8.
8484+ (#212 and #215 by @SimonFrings and #230 by @clue)
8585+8686+## 1.1.1 (2020-01-01)
8787+8888+* Fix: Fix reporting connection refused errors with `ExtUvLoop` on Linux and `StreamSelectLoop` on Windows.
8989+ (#207 and #208 by @clue)
9090+9191+* Fix: Fix unsupported EventConfig and `SEGFAULT` on shutdown with `ExtEventLoop` on Windows.
9292+ (#205 by @clue)
9393+9494+* Fix: Prevent interval overflow for timers very far in the future with `ExtUvLoop`.
9595+ (#196 by @PabloKowalczyk)
9696+9797+* Fix: Check PCNTL functions for signal support instead of PCNTL extension with `StreamSelectLoop`.
9898+ (#195 by @clue)
9999+100100+* Add `.gitattributes` to exclude dev files from exports.
101101+ (#201 by @reedy)
102102+103103+* Improve test suite to fix testing `ExtUvLoop` on Travis,
104104+ fix Travis CI builds, do not install `libuv` on legacy PHP setups,
105105+ fix failing test cases due to inaccurate timers,
106106+ run tests on Windows via Travis CI and
107107+ run tests on PHP 7.4 and simplify test matrix and test setup.
108108+ (#197 by @WyriHaximus and #202, #203, #204 and #209 by @clue)
109109+110110+## 1.1.0 (2019-02-07)
111111+112112+* New UV based event loop (ext-uv).
113113+ (#112 by @WyriHaximus)
114114+115115+* Use high resolution timer on PHP 7.3+.
116116+ (#182 by @clue)
117117+118118+* Improve PCNTL signals by using async signal dispatching if available.
119119+ (#179 by @CharlotteDunois)
120120+121121+* Improve test suite and test suite set up.
122122+ (#174 by @WyriHaximus, #181 by @clue)
123123+124124+* Fix PCNTL signals edge case.
125125+ (#183 by @clue)
126126+127127+## 1.0.0 (2018-07-11)
128128+129129+* First stable LTS release, now following [SemVer](https://semver.org/).
130130+ We'd like to emphasize that this component is production ready and battle-tested.
131131+ We plan to support all long-term support (LTS) releases for at least 24 months,
132132+ so you have a rock-solid foundation to build on top of.
133133+134134+> Contains no other changes, so it's actually fully compatible with the v0.5.3 release.
135135+136136+## 0.5.3 (2018-07-09)
137137+138138+* Improve performance by importing global functions.
139139+ (#167 by @Ocramius)
140140+141141+* Improve test suite by simplifying test bootstrap by using dev autoloader.
142142+ (#169 by @lcobucci)
143143+144144+* Minor internal changes to improved backward compatibility with PHP 5.3.
145145+ (#166 by @Donatello-za)
146146+147147+## 0.5.2 (2018-04-24)
148148+149149+* Feature: Improve memory consumption and runtime performance for `StreamSelectLoop` timers.
150150+ (#164 by @clue)
151151+152152+* Improve test suite by removing I/O dependency at `StreamSelectLoopTest` to fix Mac OS X tests.
153153+ (#161 by @nawarian)
154154+155155+## 0.5.1 (2018-04-09)
156156+157157+* Feature: New `ExtEvLoop` (PECL ext-ev) (#148 by @kaduev13)
158158+159159+## 0.5.0 (2018-04-05)
160160+161161+A major feature release with a significant documentation overhaul and long overdue API cleanup!
162162+163163+This update involves a number of BC breaks due to dropped support for deprecated
164164+functionality. We've tried hard to avoid BC breaks where possible and minimize
165165+impact otherwise. We expect that most consumers of this package will actually
166166+not be affected by any BC breaks, see below for more details.
167167+168168+We realize that the changes listed below may seem overwhelming, but we've tried
169169+to be very clear about any possible BC breaks. Don't worry: In fact, all ReactPHP
170170+components are already compatible and support both this new release as well as
171171+providing backwards compatibility with the last release.
172172+173173+* Feature / BC break: Add support for signal handling via new
174174+ `LoopInterface::addSignal()` and `LoopInterface::removeSignal()` methods.
175175+ (#104 by @WyriHaximus and #111 and #150 by @clue)
176176+177177+ ```php
178178+ $loop->addSignal(SIGINT, function () {
179179+ echo 'CTRL-C';
180180+ });
181181+ ```
182182+183183+* Feature: Significant documentation updates for `LoopInterface` and `Factory`.
184184+ (#100, #119, #126, #127, #159 and #160 by @clue, #113 by @WyriHaximus and #81 and #91 by @jsor)
185185+186186+* Feature: Add examples to ease getting started
187187+ (#99, #100 and #125 by @clue, #59 by @WyriHaximus and #143 by @jsor)
188188+189189+* Feature: Documentation for advanced timer concepts, such as monotonic time source vs wall-clock time
190190+ and high precision timers with millisecond accuracy or below.
191191+ (#130 and #157 by @clue)
192192+193193+* Feature: Documentation for advanced stream concepts, such as edge-triggered event listeners
194194+ and stream buffers and allow throwing Exception if stream resource is not supported.
195195+ (#129 and #158 by @clue)
196196+197197+* Feature: Throw `BadMethodCallException` on manual loop creation when required extension isn't installed.
198198+ (#153 by @WyriHaximus)
199199+200200+* Feature / BC break: First class support for legacy PHP 5.3 through PHP 7.2 and HHVM
201201+ and remove all `callable` type hints for consistency reasons.
202202+ (#141 and #151 by @clue)
203203+204204+* BC break: Documentation for timer API and clean up unneeded timer API.
205205+ (#102 by @clue)
206206+207207+ Remove `TimerInterface::cancel()`, use `LoopInterface::cancelTimer()` instead:
208208+209209+ ```php
210210+ // old (method invoked on timer instance)
211211+ $timer->cancel();
212212+213213+ // already supported before: invoke method on loop instance
214214+ $loop->cancelTimer($timer);
215215+ ```
216216+217217+ Remove unneeded `TimerInterface::setData()` and `TimerInterface::getData()`,
218218+ use closure binding to add arbitrary data to timer instead:
219219+220220+ ```php
221221+ // old (limited setData() and getData() only allows single variable)
222222+ $name = 'Tester';
223223+ $timer = $loop->addTimer(1.0, function ($timer) {
224224+ echo 'Hello ' . $timer->getData() . PHP_EOL;
225225+ });
226226+ $timer->setData($name);
227227+228228+ // already supported before: closure binding allows any number of variables
229229+ $name = 'Tester';
230230+ $loop->addTimer(1.0, function () use ($name) {
231231+ echo 'Hello ' . $name . PHP_EOL;
232232+ });
233233+ ```
234234+235235+ Remove unneeded `TimerInterface::getLoop()`, use closure binding instead:
236236+237237+ ```php
238238+ // old (getLoop() called on timer instance)
239239+ $loop->addTimer(0.1, function ($timer) {
240240+ $timer->getLoop()->stop();
241241+ });
242242+243243+ // already supported before: use closure binding as usual
244244+ $loop->addTimer(0.1, function () use ($loop) {
245245+ $loop->stop();
246246+ });
247247+ ```
248248+249249+* BC break: Remove unneeded `LoopInterface::isTimerActive()` and
250250+ `TimerInterface::isActive()` to reduce API surface.
251251+ (#133 by @clue)
252252+253253+ ```php
254254+ // old (method on timer instance or on loop instance)
255255+ $timer->isActive();
256256+ $loop->isTimerActive($timer);
257257+ ```
258258+259259+* BC break: Move `TimerInterface` one level up to `React\EventLoop\TimerInterface`.
260260+ (#138 by @WyriHaximus)
261261+262262+ ```php
263263+ // old (notice obsolete "Timer" namespace)
264264+ assert($timer instanceof React\EventLoop\Timer\TimerInterface);
265265+266266+ // new
267267+ assert($timer instanceof React\EventLoop\TimerInterface);
268268+ ```
269269+270270+* BC break: Remove unneeded `LoopInterface::nextTick()` (and internal `NextTickQueue`),
271271+ use `LoopInterface::futureTick()` instead.
272272+ (#30 by @clue)
273273+274274+ ```php
275275+ // old (removed)
276276+ $loop->nextTick(function () {
277277+ echo 'tick';
278278+ });
279279+280280+ // already supported before
281281+ $loop->futureTick(function () {
282282+ echo 'tick';
283283+ });
284284+ ```
285285+286286+* BC break: Remove unneeded `$loop` argument for `LoopInterface::futureTick()`
287287+ (and fix internal cyclic dependency).
288288+ (#103 by @clue)
289289+290290+ ```php
291291+ // old ($loop gets passed by default)
292292+ $loop->futureTick(function ($loop) {
293293+ $loop->stop();
294294+ });
295295+296296+ // already supported before: use closure binding as usual
297297+ $loop->futureTick(function () use ($loop) {
298298+ $loop->stop();
299299+ });
300300+ ```
301301+302302+* BC break: Remove unneeded `LoopInterface::tick()`.
303303+ (#72 by @jsor)
304304+305305+ ```php
306306+ // old (removed)
307307+ $loop->tick();
308308+309309+ // suggested work around for testing purposes only
310310+ $loop->futureTick(function () use ($loop) {
311311+ $loop->stop();
312312+ });
313313+ ```
314314+315315+* BC break: Documentation for advanced stream API and clean up unneeded stream API.
316316+ (#110 by @clue)
317317+318318+ Remove unneeded `$loop` argument for `LoopInterface::addReadStream()`
319319+ and `LoopInterface::addWriteStream()`, use closure binding instead:
320320+321321+ ```php
322322+ // old ($loop gets passed by default)
323323+ $loop->addReadStream($stream, function ($stream, $loop) {
324324+ $loop->removeReadStream($stream);
325325+ });
326326+327327+ // already supported before: use closure binding as usual
328328+ $loop->addReadStream($stream, function ($stream) use ($loop) {
329329+ $loop->removeReadStream($stream);
330330+ });
331331+ ```
332332+333333+* BC break: Remove unneeded `LoopInterface::removeStream()` method,
334334+ use `LoopInterface::removeReadStream()` and `LoopInterface::removeWriteStream()` instead.
335335+ (#118 by @clue)
336336+337337+ ```php
338338+ // old
339339+ $loop->removeStream($stream);
340340+341341+ // already supported before
342342+ $loop->removeReadStream($stream);
343343+ $loop->removeWriteStream($stream);
344344+ ```
345345+346346+* BC break: Rename `LibEventLoop` to `ExtLibeventLoop` and `LibEvLoop` to `ExtLibevLoop`
347347+ for consistent naming for event loop implementations.
348348+ (#128 by @clue)
349349+350350+* BC break: Remove optional `EventBaseConfig` argument from `ExtEventLoop`
351351+ and make its `FEATURE_FDS` enabled by default.
352352+ (#156 by @WyriHaximus)
353353+354354+* BC break: Mark all classes as final to discourage inheritance.
355355+ (#131 by @clue)
356356+357357+* Fix: Fix `ExtEventLoop` to keep track of stream resources (refcount)
358358+ (#123 by @clue)
359359+360360+* Fix: Ensure large timer interval does not overflow on 32bit systems
361361+ (#132 by @clue)
362362+363363+* Fix: Fix separately removing readable and writable side of stream when closing
364364+ (#139 by @clue)
365365+366366+* Fix: Properly clean up event watchers for `ext-event` and `ext-libev`
367367+ (#149 by @clue)
368368+369369+* Fix: Minor code cleanup and remove unneeded references
370370+ (#145 by @seregazhuk)
371371+372372+* Fix: Discourage outdated `ext-libevent` on PHP 7
373373+ (#62 by @cboden)
374374+375375+* Improve test suite by adding forward compatibility with PHPUnit 6 and PHPUnit 5,
376376+ lock Travis distro so new defaults will not break the build,
377377+ improve test suite to be less fragile and increase test timeouts,
378378+ test against PHP 7.2 and reduce fwrite() call length to one chunk.
379379+ (#106 and #144 by @clue, #120 and #124 by @carusogabriel, #147 by nawarian and #92 by @kelunik)
380380+381381+* A number of changes were originally planned for this release but have been backported
382382+ to the last `v0.4.3` already: #74, #76, #79, #81 (refs #65, #66, #67), #88 and #93
383383+384384+## 0.4.3 (2017-04-27)
385385+386386+* Bug fix: Bugfix in the usage sample code #57 (@dandelionred)
387387+* Improvement: Remove branch-alias definition #53 (@WyriHaximus)
388388+* Improvement: StreamSelectLoop: Use fresh time so Timers added during stream events are accurate #51 (@andrewminerd)
389389+* Improvement: Avoid deprecation warnings in test suite due to deprecation of getMock() in PHPUnit #68 (@martinschroeder)
390390+* Improvement: Add PHPUnit 4.8 to require-dev #69 (@shaunbramley)
391391+* Improvement: Increase test timeouts for HHVM and unify timeout handling #70 (@clue)
392392+* Improvement: Travis improvements (backported from #74) #75 (@clue)
393393+* Improvement: Test suite now uses socket pairs instead of memory streams #66 (@martinschroeder)
394394+* Improvement: StreamSelectLoop: Test suite uses signal constant names in data provider #67 (@martinschroeder)
395395+* Improvement: ExtEventLoop: No longer suppress all errors #65 (@mamciek)
396396+* Improvement: Readme cleanup #89 (@jsor)
397397+* Improvement: Restructure and improve README #90 (@jsor)
398398+* Bug fix: StreamSelectLoop: Fix erroneous zero-time sleep (backport to 0.4) #94 (@jsor)
399399+400400+## 0.4.2 (2016-03-07)
401401+402402+* Bug fix: No longer error when signals sent to StreamSelectLoop
403403+* Support HHVM and PHP7 (@ondrejmirtes, @cebe)
404404+* Feature: Added support for EventConfig for ExtEventLoop (@steverhoades)
405405+* Bug fix: Fixed an issue loading loop extension libs via autoloader (@czarpino)
406406+407407+## 0.4.1 (2014-04-13)
408408+409409+* Bug fix: null timeout in StreamSelectLoop causing 100% CPU usage (@clue)
410410+* Bug fix: v0.3.4 changes merged for v0.4.1
411411+412412+## 0.4.0 (2014-02-02)
413413+414414+* Feature: Added `EventLoopInterface::nextTick()`, implemented in all event loops (@jmalloc)
415415+* Feature: Added `EventLoopInterface::futureTick()`, implemented in all event loops (@jmalloc)
416416+* Feature: Added `ExtEventLoop` implementation using pecl/event (@jmalloc)
417417+* BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks
418418+* BC break: New method: `EventLoopInterface::nextTick()`
419419+* BC break: New method: `EventLoopInterface::futureTick()`
420420+* Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0
421421+422422+## 0.3.5 (2016-12-28)
423423+424424+This is a compatibility release that eases upgrading to the v0.4 release branch.
425425+You should consider upgrading to the v0.4 release branch.
426426+427427+* Feature: Cap min timer interval at 1µs, thus improving compatibility with v0.4
428428+ (#47 by @clue)
429429+430430+## 0.3.4 (2014-03-30)
431431+432432+* Bug fix: Changed StreamSelectLoop to use non-blocking behavior on tick() (@astephens25)
433433+434434+## 0.3.3 (2013-07-08)
435435+436436+* Bug fix: No error on removing non-existent streams (@clue)
437437+* Bug fix: Do not silently remove feof listeners in `LibEvLoop`
438438+439439+## 0.3.0 (2013-04-14)
440440+441441+* BC break: New timers API (@nrk)
442442+* BC break: Remove check on return value from stream callbacks (@nrk)
443443+444444+## 0.2.7 (2013-01-05)
445445+446446+* Bug fix: Fix libevent timers with PHP 5.3
447447+* Bug fix: Fix libevent timer cancellation (@nrk)
448448+449449+## 0.2.6 (2012-12-26)
450450+451451+* Bug fix: Plug memory issue in libevent timers (@cameronjacobson)
452452+* Bug fix: Correctly pause LibEvLoop on stop()
453453+454454+## 0.2.3 (2012-11-14)
455455+456456+* Feature: LibEvLoop, integration of `php-libev`
457457+458458+## 0.2.0 (2012-09-10)
459459+460460+* Version bump
461461+462462+## 0.1.1 (2012-07-12)
463463+464464+* Version bump
465465+466466+## 0.1.0 (2012-07-11)
467467+468468+* First tagged release
+21
vendor/react/event-loop/LICENSE
···11+The MIT License (MIT)
22+33+Copyright (c) 2012 Christian Lück, Cees-Jan Kiewiet, Jan Sorgalla, Chris Boden, Igor Wiedler
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is furnished
1010+to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121+THE SOFTWARE.
+930
vendor/react/event-loop/README.md
···11+# EventLoop
22+33+[](https://github.com/reactphp/event-loop/actions)
44+[](https://packagist.org/packages/react/event-loop)
55+66+[ReactPHP](https://reactphp.org/)'s core reactor event loop that libraries can use for evented I/O.
77+88+In order for async based libraries to be interoperable, they need to use the
99+same event loop. This component provides a common `LoopInterface` that any
1010+library can target. This allows them to be used in the same loop, with one
1111+single [`run()`](#run) call that is controlled by the user.
1212+1313+**Table of contents**
1414+1515+* [Quickstart example](#quickstart-example)
1616+* [Usage](#usage)
1717+ * [Loop](#loop)
1818+ * [Loop methods](#loop-methods)
1919+ * [Loop autorun](#loop-autorun)
2020+ * [get()](#get)
2121+ * [~~Factory~~](#factory)
2222+ * [~~create()~~](#create)
2323+ * [Loop implementations](#loop-implementations)
2424+ * [StreamSelectLoop](#streamselectloop)
2525+ * [ExtEventLoop](#exteventloop)
2626+ * [ExtEvLoop](#extevloop)
2727+ * [ExtUvLoop](#extuvloop)
2828+ * [~~ExtLibeventLoop~~](#extlibeventloop)
2929+ * [~~ExtLibevLoop~~](#extlibevloop)
3030+ * [LoopInterface](#loopinterface)
3131+ * [run()](#run)
3232+ * [stop()](#stop)
3333+ * [addTimer()](#addtimer)
3434+ * [addPeriodicTimer()](#addperiodictimer)
3535+ * [cancelTimer()](#canceltimer)
3636+ * [futureTick()](#futuretick)
3737+ * [addSignal()](#addsignal)
3838+ * [removeSignal()](#removesignal)
3939+ * [addReadStream()](#addreadstream)
4040+ * [addWriteStream()](#addwritestream)
4141+ * [removeReadStream()](#removereadstream)
4242+ * [removeWriteStream()](#removewritestream)
4343+* [Install](#install)
4444+* [Tests](#tests)
4545+* [License](#license)
4646+* [More](#more)
4747+4848+## Quickstart example
4949+5050+Here is an async HTTP server built with just the event loop.
5151+5252+```php
5353+<?php
5454+5555+use React\EventLoop\Loop;
5656+5757+require __DIR__ . '/vendor/autoload.php';
5858+5959+$server = stream_socket_server('tcp://127.0.0.1:8080');
6060+stream_set_blocking($server, false);
6161+6262+Loop::addReadStream($server, function ($server) {
6363+ $conn = stream_socket_accept($server);
6464+ $data = "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nHi\n";
6565+ Loop::addWriteStream($conn, function ($conn) use (&$data) {
6666+ $written = fwrite($conn, $data);
6767+ if ($written === strlen($data)) {
6868+ fclose($conn);
6969+ Loop::removeWriteStream($conn);
7070+ } else {
7171+ $data = substr($data, $written);
7272+ }
7373+ });
7474+});
7575+7676+Loop::addPeriodicTimer(5, function () {
7777+ $memory = memory_get_usage() / 1024;
7878+ $formatted = number_format($memory, 3).'K';
7979+ echo "Current memory usage: {$formatted}\n";
8080+});
8181+```
8282+8383+See also the [examples](examples).
8484+8585+## Usage
8686+8787+Typical applications would use the [`Loop` class](#loop) to use the default
8888+event loop like this:
8989+9090+```php
9191+use React\EventLoop\Loop;
9292+9393+$timer = Loop::addPeriodicTimer(0.1, function () {
9494+ echo 'Tick' . PHP_EOL;
9595+});
9696+9797+Loop::addTimer(1.0, function () use ($timer) {
9898+ Loop::cancelTimer($timer);
9999+ echo 'Done' . PHP_EOL;
100100+});
101101+```
102102+103103+As an alternative, you can also explicitly create an event loop instance at the
104104+beginning, reuse it throughout your program and finally run it at the end of the
105105+program like this:
106106+107107+```php
108108+$loop = React\EventLoop\Loop::get(); // or deprecated React\EventLoop\Factory::create();
109109+110110+$timer = $loop->addPeriodicTimer(0.1, function () {
111111+ echo 'Tick' . PHP_EOL;
112112+});
113113+114114+$loop->addTimer(1.0, function () use ($loop, $timer) {
115115+ $loop->cancelTimer($timer);
116116+ echo 'Done' . PHP_EOL;
117117+});
118118+119119+$loop->run();
120120+```
121121+122122+While the former is more concise, the latter is more explicit.
123123+In both cases, the program would perform the exact same steps.
124124+125125+1. The event loop instance is created at the beginning of the program. This is
126126+ implicitly done the first time you call the [`Loop` class](#loop) or
127127+ explicitly when using the deprecated [`Factory::create()` method](#create)
128128+ (or manually instantiating any of the [loop implementations](#loop-implementations)).
129129+2. The event loop is used directly or passed as an instance to library and
130130+ application code. In this example, a periodic timer is registered with the
131131+ event loop which simply outputs `Tick` every fraction of a second until another
132132+ timer stops the periodic timer after a second.
133133+3. The event loop is run at the end of the program. This is automatically done
134134+ when using the [`Loop` class](#loop) or explicitly with a single [`run()`](#run)
135135+ call at the end of the program.
136136+137137+As of `v1.2.0`, we highly recommend using the [`Loop` class](#loop).
138138+The explicit loop instructions are still valid and may still be useful in some
139139+applications, especially for a transition period towards the more concise style.
140140+141141+### Loop
142142+143143+The `Loop` class exists as a convenient global accessor for the event loop.
144144+145145+#### Loop methods
146146+147147+The `Loop` class provides all methods that exist on the [`LoopInterface`](#loopinterface)
148148+as static methods:
149149+150150+* [run()](#run)
151151+* [stop()](#stop)
152152+* [addTimer()](#addtimer)
153153+* [addPeriodicTimer()](#addperiodictimer)
154154+* [cancelTimer()](#canceltimer)
155155+* [futureTick()](#futuretick)
156156+* [addSignal()](#addsignal)
157157+* [removeSignal()](#removesignal)
158158+* [addReadStream()](#addreadstream)
159159+* [addWriteStream()](#addwritestream)
160160+* [removeReadStream()](#removereadstream)
161161+* [removeWriteStream()](#removewritestream)
162162+163163+If you're working with the event loop in your application code, it's often
164164+easiest to directly interface with the static methods defined on the `Loop` class
165165+like this:
166166+167167+```php
168168+use React\EventLoop\Loop;
169169+170170+$timer = Loop::addPeriodicTimer(0.1, function () {
171171+ echo 'Tick' . PHP_EOL;
172172+});
173173+174174+Loop::addTimer(1.0, function () use ($timer) {
175175+ Loop::cancelTimer($timer);
176176+ echo 'Done' . PHP_EOL;
177177+});
178178+```
179179+180180+On the other hand, if you're familiar with object-oriented programming (OOP) and
181181+dependency injection (DI), you may want to inject an event loop instance and
182182+invoke instance methods on the `LoopInterface` like this:
183183+184184+```php
185185+use React\EventLoop\Loop;
186186+use React\EventLoop\LoopInterface;
187187+188188+class Greeter
189189+{
190190+ private $loop;
191191+192192+ public function __construct(LoopInterface $loop)
193193+ {
194194+ $this->loop = $loop;
195195+ }
196196+197197+ public function greet(string $name)
198198+ {
199199+ $this->loop->addTimer(1.0, function () use ($name) {
200200+ echo 'Hello ' . $name . '!' . PHP_EOL;
201201+ });
202202+ }
203203+}
204204+205205+$greeter = new Greeter(Loop::get());
206206+$greeter->greet('Alice');
207207+$greeter->greet('Bob');
208208+```
209209+210210+Each static method call will be forwarded as-is to the underlying event loop
211211+instance by using the [`Loop::get()`](#get) call internally.
212212+See [`LoopInterface`](#loopinterface) for more details about available methods.
213213+214214+#### Loop autorun
215215+216216+When using the `Loop` class, it will automatically execute the loop at the end of
217217+the program. This means the following example will schedule a timer and will
218218+automatically execute the program until the timer event fires:
219219+220220+```php
221221+use React\EventLoop\Loop;
222222+223223+Loop::addTimer(1.0, function () {
224224+ echo 'Hello' . PHP_EOL;
225225+});
226226+```
227227+228228+As of `v1.2.0`, we highly recommend using the `Loop` class this way and omitting any
229229+explicit [`run()`](#run) calls. For BC reasons, the explicit [`run()`](#run)
230230+method is still valid and may still be useful in some applications, especially
231231+for a transition period towards the more concise style.
232232+233233+If you don't want the `Loop` to run automatically, you can either explicitly
234234+[`run()`](#run) or [`stop()`](#stop) it. This can be useful if you're using
235235+a global exception handler like this:
236236+237237+```php
238238+use React\EventLoop\Loop;
239239+240240+Loop::addTimer(10.0, function () {
241241+ echo 'Never happens';
242242+});
243243+244244+set_exception_handler(function (Throwable $e) {
245245+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
246246+ Loop::stop();
247247+});
248248+249249+throw new RuntimeException('Demo');
250250+```
251251+252252+#### get()
253253+254254+The `get(): LoopInterface` method can be used to
255255+get the currently active event loop instance.
256256+257257+This method will always return the same event loop instance throughout the
258258+lifetime of your application.
259259+260260+```php
261261+use React\EventLoop\Loop;
262262+use React\EventLoop\LoopInterface;
263263+264264+$loop = Loop::get();
265265+266266+assert($loop instanceof LoopInterface);
267267+assert($loop === Loop::get());
268268+```
269269+270270+This is particularly useful if you're using object-oriented programming (OOP)
271271+and dependency injection (DI). In this case, you may want to inject an event
272272+loop instance and invoke instance methods on the `LoopInterface` like this:
273273+274274+```php
275275+use React\EventLoop\Loop;
276276+use React\EventLoop\LoopInterface;
277277+278278+class Greeter
279279+{
280280+ private $loop;
281281+282282+ public function __construct(LoopInterface $loop)
283283+ {
284284+ $this->loop = $loop;
285285+ }
286286+287287+ public function greet(string $name)
288288+ {
289289+ $this->loop->addTimer(1.0, function () use ($name) {
290290+ echo 'Hello ' . $name . '!' . PHP_EOL;
291291+ });
292292+ }
293293+}
294294+295295+$greeter = new Greeter(Loop::get());
296296+$greeter->greet('Alice');
297297+$greeter->greet('Bob');
298298+```
299299+300300+See [`LoopInterface`](#loopinterface) for more details about available methods.
301301+302302+### ~~Factory~~
303303+304304+> Deprecated since v1.2.0, see [`Loop` class](#loop) instead.
305305+306306+The deprecated `Factory` class exists as a convenient way to pick the best available
307307+[event loop implementation](#loop-implementations).
308308+309309+#### ~~create()~~
310310+311311+> Deprecated since v1.2.0, see [`Loop::get()`](#get) instead.
312312+313313+The deprecated `create(): LoopInterface` method can be used to
314314+create a new event loop instance:
315315+316316+```php
317317+// deprecated
318318+$loop = React\EventLoop\Factory::create();
319319+320320+// new
321321+$loop = React\EventLoop\Loop::get();
322322+```
323323+324324+This method always returns an instance implementing [`LoopInterface`](#loopinterface),
325325+the actual [event loop implementation](#loop-implementations) is an implementation detail.
326326+327327+This method should usually only be called once at the beginning of the program.
328328+329329+### Loop implementations
330330+331331+In addition to the [`LoopInterface`](#loopinterface), there are a number of
332332+event loop implementations provided.
333333+334334+All of the event loops support these features:
335335+336336+* File descriptor polling
337337+* One-off timers
338338+* Periodic timers
339339+* Deferred execution on future loop tick
340340+341341+For most consumers of this package, the underlying event loop implementation is
342342+an implementation detail.
343343+You should use the [`Loop` class](#loop) to automatically create a new instance.
344344+345345+Advanced! If you explicitly need a certain event loop implementation, you can
346346+manually instantiate one of the following classes.
347347+Note that you may have to install the required PHP extensions for the respective
348348+event loop implementation first or they will throw a `BadMethodCallException` on creation.
349349+350350+#### StreamSelectLoop
351351+352352+A `stream_select()` based event loop.
353353+354354+This uses the [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
355355+function and is the only implementation that works out of the box with PHP.
356356+357357+This event loop works out of the box on PHP 5.3 through PHP 8+ and HHVM.
358358+This means that no installation is required and this library works on all
359359+platforms and supported PHP versions.
360360+Accordingly, the [`Loop` class](#loop) and the deprecated [`Factory`](#factory)
361361+will use this event loop by default if you do not install any of the event loop
362362+extensions listed below.
363363+364364+Under the hood, it does a simple `select` system call.
365365+This system call is limited to the maximum file descriptor number of
366366+`FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`
367367+(`m` being the maximum file descriptor number passed).
368368+This means that you may run into issues when handling thousands of streams
369369+concurrently and you may want to look into using one of the alternative
370370+event loop implementations listed below in this case.
371371+If your use case is among the many common use cases that involve handling only
372372+dozens or a few hundred streams at once, then this event loop implementation
373373+performs really well.
374374+375375+If you want to use signal handling (see also [`addSignal()`](#addsignal) below),
376376+this event loop implementation requires `ext-pcntl`.
377377+This extension is only available for Unix-like platforms and does not support
378378+Windows.
379379+It is commonly installed as part of many PHP distributions.
380380+If this extension is missing (or you're running on Windows), signal handling is
381381+not supported and throws a `BadMethodCallException` instead.
382382+383383+This event loop is known to rely on wall-clock time to schedule future timers
384384+when using any version before PHP 7.3, because a monotonic time source is
385385+only available as of PHP 7.3 (`hrtime()`).
386386+While this does not affect many common use cases, this is an important
387387+distinction for programs that rely on a high time precision or on systems
388388+that are subject to discontinuous time adjustments (time jumps).
389389+This means that if you schedule a timer to trigger in 30s on PHP < 7.3 and
390390+then adjust your system time forward by 20s, the timer may trigger in 10s.
391391+See also [`addTimer()`](#addtimer) for more details.
392392+393393+#### ExtEventLoop
394394+395395+An `ext-event` based event loop.
396396+397397+This uses the [`event` PECL extension](https://pecl.php.net/package/event),
398398+that provides an interface to `libevent` library.
399399+`libevent` itself supports a number of system-specific backends (epoll, kqueue).
400400+401401+This loop is known to work with PHP 5.4 through PHP 8+.
402402+403403+#### ExtEvLoop
404404+405405+An `ext-ev` based event loop.
406406+407407+This loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev),
408408+that provides an interface to `libev` library.
409409+`libev` itself supports a number of system-specific backends (epoll, kqueue).
410410+411411+412412+This loop is known to work with PHP 5.4 through PHP 8+.
413413+414414+#### ExtUvLoop
415415+416416+An `ext-uv` based event loop.
417417+418418+This loop uses the [`uv` PECL extension](https://pecl.php.net/package/uv),
419419+that provides an interface to `libuv` library.
420420+`libuv` itself supports a number of system-specific backends (epoll, kqueue).
421421+422422+This loop is known to work with PHP 7+.
423423+424424+#### ~~ExtLibeventLoop~~
425425+426426+> Deprecated since v1.2.0, use [`ExtEventLoop`](#exteventloop) instead.
427427+428428+An `ext-libevent` based event loop.
429429+430430+This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent),
431431+that provides an interface to `libevent` library.
432432+`libevent` itself supports a number of system-specific backends (epoll, kqueue).
433433+434434+This event loop does only work with PHP 5.
435435+An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for
436436+PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s.
437437+To reiterate: Using this event loop on PHP 7 is not recommended.
438438+Accordingly, neither the [`Loop` class](#loop) nor the deprecated
439439+[`Factory` class](#factory) will try to use this event loop on PHP 7.
440440+441441+This event loop is known to trigger a readable listener only if
442442+the stream *becomes* readable (edge-triggered) and may not trigger if the
443443+stream has already been readable from the beginning.
444444+This also implies that a stream may not be recognized as readable when data
445445+is still left in PHP's internal stream buffers.
446446+As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
447447+to disable PHP's internal read buffer in this case.
448448+See also [`addReadStream()`](#addreadstream) for more details.
449449+450450+#### ~~ExtLibevLoop~~
451451+452452+> Deprecated since v1.2.0, use [`ExtEvLoop`](#extevloop) instead.
453453+454454+An `ext-libev` based event loop.
455455+456456+This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev),
457457+that provides an interface to `libev` library.
458458+`libev` itself supports a number of system-specific backends (epoll, kqueue).
459459+460460+This loop does only work with PHP 5.
461461+An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
462462+to happen any time soon.
463463+464464+### LoopInterface
465465+466466+#### run()
467467+468468+The `run(): void` method can be used to
469469+run the event loop until there are no more tasks to perform.
470470+471471+For many applications, this method is the only directly visible
472472+invocation on the event loop.
473473+As a rule of thumb, it is usually recommended to attach everything to the
474474+same loop instance and then run the loop once at the bottom end of the
475475+application.
476476+477477+```php
478478+$loop->run();
479479+```
480480+481481+This method will keep the loop running until there are no more tasks
482482+to perform. In other words: This method will block until the last
483483+timer, stream and/or signal has been removed.
484484+485485+Likewise, it is imperative to ensure the application actually invokes
486486+this method once. Adding listeners to the loop and missing to actually
487487+run it will result in the application exiting without actually waiting
488488+for any of the attached listeners.
489489+490490+This method MUST NOT be called while the loop is already running.
491491+This method MAY be called more than once after it has explicitly been
492492+[`stop()`ped](#stop) or after it automatically stopped because it
493493+previously did no longer have anything to do.
494494+495495+#### stop()
496496+497497+The `stop(): void` method can be used to
498498+instruct a running event loop to stop.
499499+500500+This method is considered advanced usage and should be used with care.
501501+As a rule of thumb, it is usually recommended to let the loop stop
502502+only automatically when it no longer has anything to do.
503503+504504+This method can be used to explicitly instruct the event loop to stop:
505505+506506+```php
507507+$loop->addTimer(3.0, function () use ($loop) {
508508+ $loop->stop();
509509+});
510510+```
511511+512512+Calling this method on a loop instance that is not currently running or
513513+on a loop instance that has already been stopped has no effect.
514514+515515+#### addTimer()
516516+517517+The `addTimer(float $interval, callable $callback): TimerInterface` method can be used to
518518+enqueue a callback to be invoked once after the given interval.
519519+520520+The second parameter MUST be a timer callback function that accepts
521521+the timer instance as its only parameter.
522522+If you don't use the timer instance inside your timer callback function
523523+you MAY use a function which has no parameters at all.
524524+525525+The timer callback function MUST NOT throw an `Exception`.
526526+The return value of the timer callback function will be ignored and has
527527+no effect, so for performance reasons you're recommended to not return
528528+any excessive data structures.
529529+530530+This method returns a timer instance. The same timer instance will also be
531531+passed into the timer callback function as described above.
532532+You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
533533+Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
534534+the callback will be invoked only once after the given interval.
535535+536536+```php
537537+$loop->addTimer(0.8, function () {
538538+ echo 'world!' . PHP_EOL;
539539+});
540540+541541+$loop->addTimer(0.3, function () {
542542+ echo 'hello ';
543543+});
544544+```
545545+546546+See also [example #1](examples).
547547+548548+If you want to access any variables within your callback function, you
549549+can bind arbitrary data to a callback closure like this:
550550+551551+```php
552552+function hello($name, LoopInterface $loop)
553553+{
554554+ $loop->addTimer(1.0, function () use ($name) {
555555+ echo "hello $name\n";
556556+ });
557557+}
558558+559559+hello('Tester', $loop);
560560+```
561561+562562+This interface does not enforce any particular timer resolution, so
563563+special care may have to be taken if you rely on very high precision with
564564+millisecond accuracy or below. Event loop implementations SHOULD work on
565565+a best effort basis and SHOULD provide at least millisecond accuracy
566566+unless otherwise noted. Many existing event loop implementations are
567567+known to provide microsecond accuracy, but it's generally not recommended
568568+to rely on this high precision.
569569+570570+Similarly, the execution order of timers scheduled to execute at the
571571+same time (within its possible accuracy) is not guaranteed.
572572+573573+This interface suggests that event loop implementations SHOULD use a
574574+monotonic time source if available. Given that a monotonic time source is
575575+only available as of PHP 7.3 by default, event loop implementations MAY
576576+fall back to using wall-clock time.
577577+While this does not affect many common use cases, this is an important
578578+distinction for programs that rely on a high time precision or on systems
579579+that are subject to discontinuous time adjustments (time jumps).
580580+This means that if you schedule a timer to trigger in 30s and then adjust
581581+your system time forward by 20s, the timer SHOULD still trigger in 30s.
582582+See also [event loop implementations](#loop-implementations) for more details.
583583+584584+#### addPeriodicTimer()
585585+586586+The `addPeriodicTimer(float $interval, callable $callback): TimerInterface` method can be used to
587587+enqueue a callback to be invoked repeatedly after the given interval.
588588+589589+The second parameter MUST be a timer callback function that accepts
590590+the timer instance as its only parameter.
591591+If you don't use the timer instance inside your timer callback function
592592+you MAY use a function which has no parameters at all.
593593+594594+The timer callback function MUST NOT throw an `Exception`.
595595+The return value of the timer callback function will be ignored and has
596596+no effect, so for performance reasons you're recommended to not return
597597+any excessive data structures.
598598+599599+This method returns a timer instance. The same timer instance will also be
600600+passed into the timer callback function as described above.
601601+Unlike [`addTimer()`](#addtimer), this method will ensure the callback
602602+will be invoked infinitely after the given interval or until you invoke
603603+[`cancelTimer`](#canceltimer).
604604+605605+```php
606606+$timer = $loop->addPeriodicTimer(0.1, function () {
607607+ echo 'tick!' . PHP_EOL;
608608+});
609609+610610+$loop->addTimer(1.0, function () use ($loop, $timer) {
611611+ $loop->cancelTimer($timer);
612612+ echo 'Done' . PHP_EOL;
613613+});
614614+```
615615+616616+See also [example #2](examples).
617617+618618+If you want to limit the number of executions, you can bind
619619+arbitrary data to a callback closure like this:
620620+621621+```php
622622+function hello($name, LoopInterface $loop)
623623+{
624624+ $n = 3;
625625+ $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
626626+ if ($n > 0) {
627627+ --$n;
628628+ echo "hello $name\n";
629629+ } else {
630630+ $loop->cancelTimer($timer);
631631+ }
632632+ });
633633+}
634634+635635+hello('Tester', $loop);
636636+```
637637+638638+This interface does not enforce any particular timer resolution, so
639639+special care may have to be taken if you rely on very high precision with
640640+millisecond accuracy or below. Event loop implementations SHOULD work on
641641+a best effort basis and SHOULD provide at least millisecond accuracy
642642+unless otherwise noted. Many existing event loop implementations are
643643+known to provide microsecond accuracy, but it's generally not recommended
644644+to rely on this high precision.
645645+646646+Similarly, the execution order of timers scheduled to execute at the
647647+same time (within its possible accuracy) is not guaranteed.
648648+649649+This interface suggests that event loop implementations SHOULD use a
650650+monotonic time source if available. Given that a monotonic time source is
651651+only available as of PHP 7.3 by default, event loop implementations MAY
652652+fall back to using wall-clock time.
653653+While this does not affect many common use cases, this is an important
654654+distinction for programs that rely on a high time precision or on systems
655655+that are subject to discontinuous time adjustments (time jumps).
656656+This means that if you schedule a timer to trigger in 30s and then adjust
657657+your system time forward by 20s, the timer SHOULD still trigger in 30s.
658658+See also [event loop implementations](#loop-implementations) for more details.
659659+660660+Additionally, periodic timers may be subject to timer drift due to
661661+re-scheduling after each invocation. As such, it's generally not
662662+recommended to rely on this for high precision intervals with millisecond
663663+accuracy or below.
664664+665665+#### cancelTimer()
666666+667667+The `cancelTimer(TimerInterface $timer): void` method can be used to
668668+cancel a pending timer.
669669+670670+See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
671671+672672+Calling this method on a timer instance that has not been added to this
673673+loop instance or on a timer that has already been cancelled has no effect.
674674+675675+#### futureTick()
676676+677677+The `futureTick(callable $listener): void` method can be used to
678678+schedule a callback to be invoked on a future tick of the event loop.
679679+680680+This works very much similar to timers with an interval of zero seconds,
681681+but does not require the overhead of scheduling a timer queue.
682682+683683+The tick callback function MUST be able to accept zero parameters.
684684+685685+The tick callback function MUST NOT throw an `Exception`.
686686+The return value of the tick callback function will be ignored and has
687687+no effect, so for performance reasons you're recommended to not return
688688+any excessive data structures.
689689+690690+If you want to access any variables within your callback function, you
691691+can bind arbitrary data to a callback closure like this:
692692+693693+```php
694694+function hello($name, LoopInterface $loop)
695695+{
696696+ $loop->futureTick(function () use ($name) {
697697+ echo "hello $name\n";
698698+ });
699699+}
700700+701701+hello('Tester', $loop);
702702+```
703703+704704+Unlike timers, tick callbacks are guaranteed to be executed in the order
705705+they are enqueued.
706706+Also, once a callback is enqueued, there's no way to cancel this operation.
707707+708708+This is often used to break down bigger tasks into smaller steps (a form
709709+of cooperative multitasking).
710710+711711+```php
712712+$loop->futureTick(function () {
713713+ echo 'b';
714714+});
715715+$loop->futureTick(function () {
716716+ echo 'c';
717717+});
718718+echo 'a';
719719+```
720720+721721+See also [example #3](examples).
722722+723723+#### addSignal()
724724+725725+The `addSignal(int $signal, callable $listener): void` method can be used to
726726+register a listener to be notified when a signal has been caught by this process.
727727+728728+This is useful to catch user interrupt signals or shutdown signals from
729729+tools like `supervisor` or `systemd`.
730730+731731+The second parameter MUST be a listener callback function that accepts
732732+the signal as its only parameter.
733733+If you don't use the signal inside your listener callback function
734734+you MAY use a function which has no parameters at all.
735735+736736+The listener callback function MUST NOT throw an `Exception`.
737737+The return value of the listener callback function will be ignored and has
738738+no effect, so for performance reasons you're recommended to not return
739739+any excessive data structures.
740740+741741+```php
742742+$loop->addSignal(SIGINT, function (int $signal) {
743743+ echo 'Caught user interrupt signal' . PHP_EOL;
744744+});
745745+```
746746+747747+See also [example #4](examples).
748748+749749+Signaling is only available on Unix-like platforms, Windows isn't
750750+supported due to operating system limitations.
751751+This method may throw a `BadMethodCallException` if signals aren't
752752+supported on this platform, for example when required extensions are
753753+missing.
754754+755755+**Note: A listener can only be added once to the same signal, any
756756+attempts to add it more than once will be ignored.**
757757+758758+#### removeSignal()
759759+760760+The `removeSignal(int $signal, callable $listener): void` method can be used to
761761+remove a previously added signal listener.
762762+763763+```php
764764+$loop->removeSignal(SIGINT, $listener);
765765+```
766766+767767+Any attempts to remove listeners that aren't registered will be ignored.
768768+769769+#### addReadStream()
770770+771771+> Advanced! Note that this low-level API is considered advanced usage.
772772+ Most use cases should probably use the higher-level
773773+ [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
774774+ instead.
775775+776776+The `addReadStream(resource $stream, callable $callback): void` method can be used to
777777+register a listener to be notified when a stream is ready to read.
778778+779779+The first parameter MUST be a valid stream resource that supports
780780+checking whether it is ready to read by this loop implementation.
781781+A single stream resource MUST NOT be added more than once.
782782+Instead, either call [`removeReadStream()`](#removereadstream) first or
783783+react to this event with a single listener and then dispatch from this
784784+listener. This method MAY throw an `Exception` if the given resource type
785785+is not supported by this loop implementation.
786786+787787+The second parameter MUST be a listener callback function that accepts
788788+the stream resource as its only parameter.
789789+If you don't use the stream resource inside your listener callback function
790790+you MAY use a function which has no parameters at all.
791791+792792+The listener callback function MUST NOT throw an `Exception`.
793793+The return value of the listener callback function will be ignored and has
794794+no effect, so for performance reasons you're recommended to not return
795795+any excessive data structures.
796796+797797+If you want to access any variables within your callback function, you
798798+can bind arbitrary data to a callback closure like this:
799799+800800+```php
801801+$loop->addReadStream($stream, function ($stream) use ($name) {
802802+ echo $name . ' said: ' . fread($stream);
803803+});
804804+```
805805+806806+See also [example #11](examples).
807807+808808+You can invoke [`removeReadStream()`](#removereadstream) to remove the
809809+read event listener for this stream.
810810+811811+The execution order of listeners when multiple streams become ready at
812812+the same time is not guaranteed.
813813+814814+Some event loop implementations are known to only trigger the listener if
815815+the stream *becomes* readable (edge-triggered) and may not trigger if the
816816+stream has already been readable from the beginning.
817817+This also implies that a stream may not be recognized as readable when data
818818+is still left in PHP's internal stream buffers.
819819+As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
820820+to disable PHP's internal read buffer in this case.
821821+822822+#### addWriteStream()
823823+824824+> Advanced! Note that this low-level API is considered advanced usage.
825825+ Most use cases should probably use the higher-level
826826+ [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
827827+ instead.
828828+829829+The `addWriteStream(resource $stream, callable $callback): void` method can be used to
830830+register a listener to be notified when a stream is ready to write.
831831+832832+The first parameter MUST be a valid stream resource that supports
833833+checking whether it is ready to write by this loop implementation.
834834+A single stream resource MUST NOT be added more than once.
835835+Instead, either call [`removeWriteStream()`](#removewritestream) first or
836836+react to this event with a single listener and then dispatch from this
837837+listener. This method MAY throw an `Exception` if the given resource type
838838+is not supported by this loop implementation.
839839+840840+The second parameter MUST be a listener callback function that accepts
841841+the stream resource as its only parameter.
842842+If you don't use the stream resource inside your listener callback function
843843+you MAY use a function which has no parameters at all.
844844+845845+The listener callback function MUST NOT throw an `Exception`.
846846+The return value of the listener callback function will be ignored and has
847847+no effect, so for performance reasons you're recommended to not return
848848+any excessive data structures.
849849+850850+If you want to access any variables within your callback function, you
851851+can bind arbitrary data to a callback closure like this:
852852+853853+```php
854854+$loop->addWriteStream($stream, function ($stream) use ($name) {
855855+ fwrite($stream, 'Hello ' . $name);
856856+});
857857+```
858858+859859+See also [example #12](examples).
860860+861861+You can invoke [`removeWriteStream()`](#removewritestream) to remove the
862862+write event listener for this stream.
863863+864864+The execution order of listeners when multiple streams become ready at
865865+the same time is not guaranteed.
866866+867867+#### removeReadStream()
868868+869869+The `removeReadStream(resource $stream): void` method can be used to
870870+remove the read event listener for the given stream.
871871+872872+Removing a stream from the loop that has already been removed or trying
873873+to remove a stream that was never added or is invalid has no effect.
874874+875875+#### removeWriteStream()
876876+877877+The `removeWriteStream(resource $stream): void` method can be used to
878878+remove the write event listener for the given stream.
879879+880880+Removing a stream from the loop that has already been removed or trying
881881+to remove a stream that was never added or is invalid has no effect.
882882+883883+## Install
884884+885885+The recommended way to install this library is [through Composer](https://getcomposer.org/).
886886+[New to Composer?](https://getcomposer.org/doc/00-intro.md)
887887+888888+This project follows [SemVer](https://semver.org/).
889889+This will install the latest supported version:
890890+891891+```bash
892892+composer require react/event-loop:^1.5
893893+```
894894+895895+See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
896896+897897+This project aims to run on any platform and thus does not require any PHP
898898+extensions and supports running on legacy PHP 5.3 through current PHP 8+ and
899899+HHVM.
900900+It's *highly recommended to use the latest supported PHP version* for this project.
901901+902902+Installing any of the event loop extensions is suggested, but entirely optional.
903903+See also [event loop implementations](#loop-implementations) for more details.
904904+905905+## Tests
906906+907907+To run the test suite, you first need to clone this repo and then install all
908908+dependencies [through Composer](https://getcomposer.org/):
909909+910910+```bash
911911+composer install
912912+```
913913+914914+To run the test suite, go to the project root and run:
915915+916916+```bash
917917+vendor/bin/phpunit
918918+```
919919+920920+## License
921921+922922+MIT, see [LICENSE file](LICENSE).
923923+924924+## More
925925+926926+* See our [Stream component](https://github.com/reactphp/stream) for more
927927+ information on how streams are used in real-world applications.
928928+* See our [users wiki](https://github.com/reactphp/react/wiki/Users) and the
929929+ [dependents on Packagist](https://packagist.org/packages/react/event-loop/dependents)
930930+ for a list of packages that use the EventLoop in real-world applications.
···11+<?php
22+33+namespace React\EventLoop;
44+55+use Ev;
66+use EvIo;
77+use EvLoop;
88+use React\EventLoop\Tick\FutureTickQueue;
99+use React\EventLoop\Timer\Timer;
1010+use SplObjectStorage;
1111+1212+/**
1313+ * An `ext-ev` based event loop.
1414+ *
1515+ * This loop uses the [`ev` PECL extension](https://pecl.php.net/package/ev),
1616+ * that provides an interface to `libev` library.
1717+ * `libev` itself supports a number of system-specific backends (epoll, kqueue).
1818+ *
1919+ * This loop is known to work with PHP 5.4 through PHP 8+.
2020+ *
2121+ * @see http://php.net/manual/en/book.ev.php
2222+ * @see https://bitbucket.org/osmanov/pecl-ev/overview
2323+ */
2424+class ExtEvLoop implements LoopInterface
2525+{
2626+ /**
2727+ * @var EvLoop
2828+ */
2929+ private $loop;
3030+3131+ /**
3232+ * @var FutureTickQueue
3333+ */
3434+ private $futureTickQueue;
3535+3636+ /**
3737+ * @var SplObjectStorage
3838+ */
3939+ private $timers;
4040+4141+ /**
4242+ * @var EvIo[]
4343+ */
4444+ private $readStreams = array();
4545+4646+ /**
4747+ * @var EvIo[]
4848+ */
4949+ private $writeStreams = array();
5050+5151+ /**
5252+ * @var bool
5353+ */
5454+ private $running;
5555+5656+ /**
5757+ * @var SignalsHandler
5858+ */
5959+ private $signals;
6060+6161+ /**
6262+ * @var \EvSignal[]
6363+ */
6464+ private $signalEvents = array();
6565+6666+ public function __construct()
6767+ {
6868+ $this->loop = new EvLoop();
6969+ $this->futureTickQueue = new FutureTickQueue();
7070+ $this->timers = new SplObjectStorage();
7171+ $this->signals = new SignalsHandler();
7272+ }
7373+7474+ public function addReadStream($stream, $listener)
7575+ {
7676+ $key = (int)$stream;
7777+7878+ if (isset($this->readStreams[$key])) {
7979+ return;
8080+ }
8181+8282+ $callback = $this->getStreamListenerClosure($stream, $listener);
8383+ $event = $this->loop->io($stream, Ev::READ, $callback);
8484+ $this->readStreams[$key] = $event;
8585+ }
8686+8787+ /**
8888+ * @param resource $stream
8989+ * @param callable $listener
9090+ *
9191+ * @return \Closure
9292+ */
9393+ private function getStreamListenerClosure($stream, $listener)
9494+ {
9595+ return function () use ($stream, $listener) {
9696+ \call_user_func($listener, $stream);
9797+ };
9898+ }
9999+100100+ public function addWriteStream($stream, $listener)
101101+ {
102102+ $key = (int)$stream;
103103+104104+ if (isset($this->writeStreams[$key])) {
105105+ return;
106106+ }
107107+108108+ $callback = $this->getStreamListenerClosure($stream, $listener);
109109+ $event = $this->loop->io($stream, Ev::WRITE, $callback);
110110+ $this->writeStreams[$key] = $event;
111111+ }
112112+113113+ public function removeReadStream($stream)
114114+ {
115115+ $key = (int)$stream;
116116+117117+ if (!isset($this->readStreams[$key])) {
118118+ return;
119119+ }
120120+121121+ $this->readStreams[$key]->stop();
122122+ unset($this->readStreams[$key]);
123123+ }
124124+125125+ public function removeWriteStream($stream)
126126+ {
127127+ $key = (int)$stream;
128128+129129+ if (!isset($this->writeStreams[$key])) {
130130+ return;
131131+ }
132132+133133+ $this->writeStreams[$key]->stop();
134134+ unset($this->writeStreams[$key]);
135135+ }
136136+137137+ public function addTimer($interval, $callback)
138138+ {
139139+ $timer = new Timer($interval, $callback, false);
140140+141141+ $that = $this;
142142+ $timers = $this->timers;
143143+ $callback = function () use ($timer, $timers, $that) {
144144+ \call_user_func($timer->getCallback(), $timer);
145145+146146+ if ($timers->contains($timer)) {
147147+ $that->cancelTimer($timer);
148148+ }
149149+ };
150150+151151+ $event = $this->loop->timer($timer->getInterval(), 0.0, $callback);
152152+ $this->timers->attach($timer, $event);
153153+154154+ return $timer;
155155+ }
156156+157157+ public function addPeriodicTimer($interval, $callback)
158158+ {
159159+ $timer = new Timer($interval, $callback, true);
160160+161161+ $callback = function () use ($timer) {
162162+ \call_user_func($timer->getCallback(), $timer);
163163+ };
164164+165165+ $event = $this->loop->timer($timer->getInterval(), $timer->getInterval(), $callback);
166166+ $this->timers->attach($timer, $event);
167167+168168+ return $timer;
169169+ }
170170+171171+ public function cancelTimer(TimerInterface $timer)
172172+ {
173173+ if (!isset($this->timers[$timer])) {
174174+ return;
175175+ }
176176+177177+ $event = $this->timers[$timer];
178178+ $event->stop();
179179+ $this->timers->detach($timer);
180180+ }
181181+182182+ public function futureTick($listener)
183183+ {
184184+ $this->futureTickQueue->add($listener);
185185+ }
186186+187187+ public function run()
188188+ {
189189+ $this->running = true;
190190+191191+ while ($this->running) {
192192+ $this->futureTickQueue->tick();
193193+194194+ $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
195195+ $wasJustStopped = !$this->running;
196196+ $nothingLeftToDo = !$this->readStreams
197197+ && !$this->writeStreams
198198+ && !$this->timers->count()
199199+ && $this->signals->isEmpty();
200200+201201+ $flags = Ev::RUN_ONCE;
202202+ if ($wasJustStopped || $hasPendingCallbacks) {
203203+ $flags |= Ev::RUN_NOWAIT;
204204+ } elseif ($nothingLeftToDo) {
205205+ break;
206206+ }
207207+208208+ $this->loop->run($flags);
209209+ }
210210+ }
211211+212212+ public function stop()
213213+ {
214214+ $this->running = false;
215215+ }
216216+217217+ public function __destruct()
218218+ {
219219+ /** @var TimerInterface $timer */
220220+ foreach ($this->timers as $timer) {
221221+ $this->cancelTimer($timer);
222222+ }
223223+224224+ foreach ($this->readStreams as $key => $stream) {
225225+ $this->removeReadStream($key);
226226+ }
227227+228228+ foreach ($this->writeStreams as $key => $stream) {
229229+ $this->removeWriteStream($key);
230230+ }
231231+ }
232232+233233+ public function addSignal($signal, $listener)
234234+ {
235235+ $this->signals->add($signal, $listener);
236236+237237+ if (!isset($this->signalEvents[$signal])) {
238238+ $this->signalEvents[$signal] = $this->loop->signal($signal, function() use ($signal) {
239239+ $this->signals->call($signal);
240240+ });
241241+ }
242242+ }
243243+244244+ public function removeSignal($signal, $listener)
245245+ {
246246+ $this->signals->remove($signal, $listener);
247247+248248+ if (isset($this->signalEvents[$signal])) {
249249+ $this->signalEvents[$signal]->stop();
250250+ unset($this->signalEvents[$signal]);
251251+ }
252252+ }
253253+}
+275
vendor/react/event-loop/src/ExtEventLoop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+use BadMethodCallException;
66+use Event;
77+use EventBase;
88+use React\EventLoop\Tick\FutureTickQueue;
99+use React\EventLoop\Timer\Timer;
1010+use SplObjectStorage;
1111+1212+/**
1313+ * An `ext-event` based event loop.
1414+ *
1515+ * This uses the [`event` PECL extension](https://pecl.php.net/package/event),
1616+ * that provides an interface to `libevent` library.
1717+ * `libevent` itself supports a number of system-specific backends (epoll, kqueue).
1818+ *
1919+ * This loop is known to work with PHP 5.4 through PHP 8+.
2020+ *
2121+ * @link https://pecl.php.net/package/event
2222+ */
2323+final class ExtEventLoop implements LoopInterface
2424+{
2525+ private $eventBase;
2626+ private $futureTickQueue;
2727+ private $timerCallback;
2828+ private $timerEvents;
2929+ private $streamCallback;
3030+ private $readEvents = array();
3131+ private $writeEvents = array();
3232+ private $readListeners = array();
3333+ private $writeListeners = array();
3434+ private $readRefs = array();
3535+ private $writeRefs = array();
3636+ private $running;
3737+ private $signals;
3838+ private $signalEvents = array();
3939+4040+ public function __construct()
4141+ {
4242+ if (!\class_exists('EventBase', false)) {
4343+ throw new BadMethodCallException('Cannot create ExtEventLoop, ext-event extension missing');
4444+ }
4545+4646+ // support arbitrary file descriptors and not just sockets
4747+ // Windows only has limited file descriptor support, so do not require this (will fail otherwise)
4848+ // @link http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html#_setting_up_a_complicated_event_base
4949+ $config = new \EventConfig();
5050+ if (\DIRECTORY_SEPARATOR !== '\\') {
5151+ $config->requireFeatures(\EventConfig::FEATURE_FDS);
5252+ }
5353+5454+ $this->eventBase = new EventBase($config);
5555+ $this->futureTickQueue = new FutureTickQueue();
5656+ $this->timerEvents = new SplObjectStorage();
5757+ $this->signals = new SignalsHandler();
5858+5959+ $this->createTimerCallback();
6060+ $this->createStreamCallback();
6161+ }
6262+6363+ public function __destruct()
6464+ {
6565+ // explicitly clear all references to Event objects to prevent SEGFAULTs on Windows
6666+ foreach ($this->timerEvents as $timer) {
6767+ $this->timerEvents->detach($timer);
6868+ }
6969+7070+ $this->readEvents = array();
7171+ $this->writeEvents = array();
7272+ }
7373+7474+ public function addReadStream($stream, $listener)
7575+ {
7676+ $key = (int) $stream;
7777+ if (isset($this->readListeners[$key])) {
7878+ return;
7979+ }
8080+8181+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::READ, $this->streamCallback);
8282+ $event->add();
8383+ $this->readEvents[$key] = $event;
8484+ $this->readListeners[$key] = $listener;
8585+8686+ // ext-event does not increase refcount on stream resources for PHP 7+
8787+ // manually keep track of stream resource to prevent premature garbage collection
8888+ if (\PHP_VERSION_ID >= 70000) {
8989+ $this->readRefs[$key] = $stream;
9090+ }
9191+ }
9292+9393+ public function addWriteStream($stream, $listener)
9494+ {
9595+ $key = (int) $stream;
9696+ if (isset($this->writeListeners[$key])) {
9797+ return;
9898+ }
9999+100100+ $event = new Event($this->eventBase, $stream, Event::PERSIST | Event::WRITE, $this->streamCallback);
101101+ $event->add();
102102+ $this->writeEvents[$key] = $event;
103103+ $this->writeListeners[$key] = $listener;
104104+105105+ // ext-event does not increase refcount on stream resources for PHP 7+
106106+ // manually keep track of stream resource to prevent premature garbage collection
107107+ if (\PHP_VERSION_ID >= 70000) {
108108+ $this->writeRefs[$key] = $stream;
109109+ }
110110+ }
111111+112112+ public function removeReadStream($stream)
113113+ {
114114+ $key = (int) $stream;
115115+116116+ if (isset($this->readEvents[$key])) {
117117+ $this->readEvents[$key]->free();
118118+ unset(
119119+ $this->readEvents[$key],
120120+ $this->readListeners[$key],
121121+ $this->readRefs[$key]
122122+ );
123123+ }
124124+ }
125125+126126+ public function removeWriteStream($stream)
127127+ {
128128+ $key = (int) $stream;
129129+130130+ if (isset($this->writeEvents[$key])) {
131131+ $this->writeEvents[$key]->free();
132132+ unset(
133133+ $this->writeEvents[$key],
134134+ $this->writeListeners[$key],
135135+ $this->writeRefs[$key]
136136+ );
137137+ }
138138+ }
139139+140140+ public function addTimer($interval, $callback)
141141+ {
142142+ $timer = new Timer($interval, $callback, false);
143143+144144+ $this->scheduleTimer($timer);
145145+146146+ return $timer;
147147+ }
148148+149149+ public function addPeriodicTimer($interval, $callback)
150150+ {
151151+ $timer = new Timer($interval, $callback, true);
152152+153153+ $this->scheduleTimer($timer);
154154+155155+ return $timer;
156156+ }
157157+158158+ public function cancelTimer(TimerInterface $timer)
159159+ {
160160+ if ($this->timerEvents->contains($timer)) {
161161+ $this->timerEvents[$timer]->free();
162162+ $this->timerEvents->detach($timer);
163163+ }
164164+ }
165165+166166+ public function futureTick($listener)
167167+ {
168168+ $this->futureTickQueue->add($listener);
169169+ }
170170+171171+ public function addSignal($signal, $listener)
172172+ {
173173+ $this->signals->add($signal, $listener);
174174+175175+ if (!isset($this->signalEvents[$signal])) {
176176+ $this->signalEvents[$signal] = Event::signal($this->eventBase, $signal, array($this->signals, 'call'));
177177+ $this->signalEvents[$signal]->add();
178178+ }
179179+ }
180180+181181+ public function removeSignal($signal, $listener)
182182+ {
183183+ $this->signals->remove($signal, $listener);
184184+185185+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
186186+ $this->signalEvents[$signal]->free();
187187+ unset($this->signalEvents[$signal]);
188188+ }
189189+ }
190190+191191+ public function run()
192192+ {
193193+ $this->running = true;
194194+195195+ while ($this->running) {
196196+ $this->futureTickQueue->tick();
197197+198198+ $flags = EventBase::LOOP_ONCE;
199199+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
200200+ $flags |= EventBase::LOOP_NONBLOCK;
201201+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
202202+ break;
203203+ }
204204+205205+ $this->eventBase->loop($flags);
206206+ }
207207+ }
208208+209209+ public function stop()
210210+ {
211211+ $this->running = false;
212212+ }
213213+214214+ /**
215215+ * Schedule a timer for execution.
216216+ *
217217+ * @param TimerInterface $timer
218218+ */
219219+ private function scheduleTimer(TimerInterface $timer)
220220+ {
221221+ $flags = Event::TIMEOUT;
222222+223223+ if ($timer->isPeriodic()) {
224224+ $flags |= Event::PERSIST;
225225+ }
226226+227227+ $event = new Event($this->eventBase, -1, $flags, $this->timerCallback, $timer);
228228+ $this->timerEvents[$timer] = $event;
229229+230230+ $event->add($timer->getInterval());
231231+ }
232232+233233+ /**
234234+ * Create a callback used as the target of timer events.
235235+ *
236236+ * A reference is kept to the callback for the lifetime of the loop
237237+ * to prevent "Cannot destroy active lambda function" fatal error from
238238+ * the event extension.
239239+ */
240240+ private function createTimerCallback()
241241+ {
242242+ $timers = $this->timerEvents;
243243+ $this->timerCallback = function ($_, $__, $timer) use ($timers) {
244244+ \call_user_func($timer->getCallback(), $timer);
245245+246246+ if (!$timer->isPeriodic() && $timers->contains($timer)) {
247247+ $this->cancelTimer($timer);
248248+ }
249249+ };
250250+ }
251251+252252+ /**
253253+ * Create a callback used as the target of stream events.
254254+ *
255255+ * A reference is kept to the callback for the lifetime of the loop
256256+ * to prevent "Cannot destroy active lambda function" fatal error from
257257+ * the event extension.
258258+ */
259259+ private function createStreamCallback()
260260+ {
261261+ $read =& $this->readListeners;
262262+ $write =& $this->writeListeners;
263263+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
264264+ $key = (int) $stream;
265265+266266+ if (Event::READ === (Event::READ & $flags) && isset($read[$key])) {
267267+ \call_user_func($read[$key], $stream);
268268+ }
269269+270270+ if (Event::WRITE === (Event::WRITE & $flags) && isset($write[$key])) {
271271+ \call_user_func($write[$key], $stream);
272272+ }
273273+ };
274274+ }
275275+}
+201
vendor/react/event-loop/src/ExtLibevLoop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+use BadMethodCallException;
66+use libev\EventLoop;
77+use libev\IOEvent;
88+use libev\SignalEvent;
99+use libev\TimerEvent;
1010+use React\EventLoop\Tick\FutureTickQueue;
1111+use React\EventLoop\Timer\Timer;
1212+use SplObjectStorage;
1313+1414+/**
1515+ * [Deprecated] An `ext-libev` based event loop.
1616+ *
1717+ * This uses an [unofficial `libev` extension](https://github.com/m4rw3r/php-libev),
1818+ * that provides an interface to `libev` library.
1919+ * `libev` itself supports a number of system-specific backends (epoll, kqueue).
2020+ *
2121+ * This loop does only work with PHP 5.
2222+ * An update for PHP 7 is [unlikely](https://github.com/m4rw3r/php-libev/issues/8)
2323+ * to happen any time soon.
2424+ *
2525+ * @see https://github.com/m4rw3r/php-libev
2626+ * @see https://gist.github.com/1688204
2727+ * @deprecated 1.2.0, use [`ExtEvLoop`](#extevloop) instead.
2828+ */
2929+final class ExtLibevLoop implements LoopInterface
3030+{
3131+ private $loop;
3232+ private $futureTickQueue;
3333+ private $timerEvents;
3434+ private $readEvents = array();
3535+ private $writeEvents = array();
3636+ private $running;
3737+ private $signals;
3838+ private $signalEvents = array();
3939+4040+ public function __construct()
4141+ {
4242+ if (!\class_exists('libev\EventLoop', false)) {
4343+ throw new BadMethodCallException('Cannot create ExtLibevLoop, ext-libev extension missing');
4444+ }
4545+4646+ $this->loop = new EventLoop();
4747+ $this->futureTickQueue = new FutureTickQueue();
4848+ $this->timerEvents = new SplObjectStorage();
4949+ $this->signals = new SignalsHandler();
5050+ }
5151+5252+ public function addReadStream($stream, $listener)
5353+ {
5454+ if (isset($this->readEvents[(int) $stream])) {
5555+ return;
5656+ }
5757+5858+ $callback = function () use ($stream, $listener) {
5959+ \call_user_func($listener, $stream);
6060+ };
6161+6262+ $event = new IOEvent($callback, $stream, IOEvent::READ);
6363+ $this->loop->add($event);
6464+6565+ $this->readEvents[(int) $stream] = $event;
6666+ }
6767+6868+ public function addWriteStream($stream, $listener)
6969+ {
7070+ if (isset($this->writeEvents[(int) $stream])) {
7171+ return;
7272+ }
7373+7474+ $callback = function () use ($stream, $listener) {
7575+ \call_user_func($listener, $stream);
7676+ };
7777+7878+ $event = new IOEvent($callback, $stream, IOEvent::WRITE);
7979+ $this->loop->add($event);
8080+8181+ $this->writeEvents[(int) $stream] = $event;
8282+ }
8383+8484+ public function removeReadStream($stream)
8585+ {
8686+ $key = (int) $stream;
8787+8888+ if (isset($this->readEvents[$key])) {
8989+ $this->readEvents[$key]->stop();
9090+ $this->loop->remove($this->readEvents[$key]);
9191+ unset($this->readEvents[$key]);
9292+ }
9393+ }
9494+9595+ public function removeWriteStream($stream)
9696+ {
9797+ $key = (int) $stream;
9898+9999+ if (isset($this->writeEvents[$key])) {
100100+ $this->writeEvents[$key]->stop();
101101+ $this->loop->remove($this->writeEvents[$key]);
102102+ unset($this->writeEvents[$key]);
103103+ }
104104+ }
105105+106106+ public function addTimer($interval, $callback)
107107+ {
108108+ $timer = new Timer( $interval, $callback, false);
109109+110110+ $that = $this;
111111+ $timers = $this->timerEvents;
112112+ $callback = function () use ($timer, $timers, $that) {
113113+ \call_user_func($timer->getCallback(), $timer);
114114+115115+ if ($timers->contains($timer)) {
116116+ $that->cancelTimer($timer);
117117+ }
118118+ };
119119+120120+ $event = new TimerEvent($callback, $timer->getInterval());
121121+ $this->timerEvents->attach($timer, $event);
122122+ $this->loop->add($event);
123123+124124+ return $timer;
125125+ }
126126+127127+ public function addPeriodicTimer($interval, $callback)
128128+ {
129129+ $timer = new Timer($interval, $callback, true);
130130+131131+ $callback = function () use ($timer) {
132132+ \call_user_func($timer->getCallback(), $timer);
133133+ };
134134+135135+ $event = new TimerEvent($callback, $timer->getInterval(), $timer->getInterval());
136136+ $this->timerEvents->attach($timer, $event);
137137+ $this->loop->add($event);
138138+139139+ return $timer;
140140+ }
141141+142142+ public function cancelTimer(TimerInterface $timer)
143143+ {
144144+ if (isset($this->timerEvents[$timer])) {
145145+ $this->loop->remove($this->timerEvents[$timer]);
146146+ $this->timerEvents->detach($timer);
147147+ }
148148+ }
149149+150150+ public function futureTick($listener)
151151+ {
152152+ $this->futureTickQueue->add($listener);
153153+ }
154154+155155+ public function addSignal($signal, $listener)
156156+ {
157157+ $this->signals->add($signal, $listener);
158158+159159+ if (!isset($this->signalEvents[$signal])) {
160160+ $signals = $this->signals;
161161+ $this->signalEvents[$signal] = new SignalEvent(function () use ($signals, $signal) {
162162+ $signals->call($signal);
163163+ }, $signal);
164164+ $this->loop->add($this->signalEvents[$signal]);
165165+ }
166166+ }
167167+168168+ public function removeSignal($signal, $listener)
169169+ {
170170+ $this->signals->remove($signal, $listener);
171171+172172+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
173173+ $this->signalEvents[$signal]->stop();
174174+ $this->loop->remove($this->signalEvents[$signal]);
175175+ unset($this->signalEvents[$signal]);
176176+ }
177177+ }
178178+179179+ public function run()
180180+ {
181181+ $this->running = true;
182182+183183+ while ($this->running) {
184184+ $this->futureTickQueue->tick();
185185+186186+ $flags = EventLoop::RUN_ONCE;
187187+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
188188+ $flags |= EventLoop::RUN_NOWAIT;
189189+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
190190+ break;
191191+ }
192192+193193+ $this->loop->run($flags);
194194+ }
195195+ }
196196+197197+ public function stop()
198198+ {
199199+ $this->running = false;
200200+ }
201201+}
+285
vendor/react/event-loop/src/ExtLibeventLoop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+use BadMethodCallException;
66+use Event;
77+use EventBase;
88+use React\EventLoop\Tick\FutureTickQueue;
99+use React\EventLoop\Timer\Timer;
1010+use SplObjectStorage;
1111+1212+/**
1313+ * [Deprecated] An `ext-libevent` based event loop.
1414+ *
1515+ * This uses the [`libevent` PECL extension](https://pecl.php.net/package/libevent),
1616+ * that provides an interface to `libevent` library.
1717+ * `libevent` itself supports a number of system-specific backends (epoll, kqueue).
1818+ *
1919+ * This event loop does only work with PHP 5.
2020+ * An [unofficial update](https://github.com/php/pecl-event-libevent/pull/2) for
2121+ * PHP 7 does exist, but it is known to cause regular crashes due to `SEGFAULT`s.
2222+ * To reiterate: Using this event loop on PHP 7 is not recommended.
2323+ * Accordingly, neither the [`Loop` class](#loop) nor the deprecated
2424+ * [`Factory` class](#factory) will try to use this event loop on PHP 7.
2525+ *
2626+ * This event loop is known to trigger a readable listener only if
2727+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
2828+ * stream has already been readable from the beginning.
2929+ * This also implies that a stream may not be recognized as readable when data
3030+ * is still left in PHP's internal stream buffers.
3131+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
3232+ * to disable PHP's internal read buffer in this case.
3333+ * See also [`addReadStream()`](#addreadstream) for more details.
3434+ *
3535+ * @link https://pecl.php.net/package/libevent
3636+ * @deprecated 1.2.0, use [`ExtEventLoop`](#exteventloop) instead.
3737+ */
3838+final class ExtLibeventLoop implements LoopInterface
3939+{
4040+ /** @internal */
4141+ const MICROSECONDS_PER_SECOND = 1000000;
4242+4343+ private $eventBase;
4444+ private $futureTickQueue;
4545+ private $timerCallback;
4646+ private $timerEvents;
4747+ private $streamCallback;
4848+ private $readEvents = array();
4949+ private $writeEvents = array();
5050+ private $readListeners = array();
5151+ private $writeListeners = array();
5252+ private $running;
5353+ private $signals;
5454+ private $signalEvents = array();
5555+5656+ public function __construct()
5757+ {
5858+ if (!\function_exists('event_base_new')) {
5959+ throw new BadMethodCallException('Cannot create ExtLibeventLoop, ext-libevent extension missing');
6060+ }
6161+6262+ $this->eventBase = \event_base_new();
6363+ $this->futureTickQueue = new FutureTickQueue();
6464+ $this->timerEvents = new SplObjectStorage();
6565+ $this->signals = new SignalsHandler();
6666+6767+ $this->createTimerCallback();
6868+ $this->createStreamCallback();
6969+ }
7070+7171+ public function addReadStream($stream, $listener)
7272+ {
7373+ $key = (int) $stream;
7474+ if (isset($this->readListeners[$key])) {
7575+ return;
7676+ }
7777+7878+ $event = \event_new();
7979+ \event_set($event, $stream, \EV_PERSIST | \EV_READ, $this->streamCallback);
8080+ \event_base_set($event, $this->eventBase);
8181+ \event_add($event);
8282+8383+ $this->readEvents[$key] = $event;
8484+ $this->readListeners[$key] = $listener;
8585+ }
8686+8787+ public function addWriteStream($stream, $listener)
8888+ {
8989+ $key = (int) $stream;
9090+ if (isset($this->writeListeners[$key])) {
9191+ return;
9292+ }
9393+9494+ $event = \event_new();
9595+ \event_set($event, $stream, \EV_PERSIST | \EV_WRITE, $this->streamCallback);
9696+ \event_base_set($event, $this->eventBase);
9797+ \event_add($event);
9898+9999+ $this->writeEvents[$key] = $event;
100100+ $this->writeListeners[$key] = $listener;
101101+ }
102102+103103+ public function removeReadStream($stream)
104104+ {
105105+ $key = (int) $stream;
106106+107107+ if (isset($this->readListeners[$key])) {
108108+ $event = $this->readEvents[$key];
109109+ \event_del($event);
110110+ \event_free($event);
111111+112112+ unset(
113113+ $this->readEvents[$key],
114114+ $this->readListeners[$key]
115115+ );
116116+ }
117117+ }
118118+119119+ public function removeWriteStream($stream)
120120+ {
121121+ $key = (int) $stream;
122122+123123+ if (isset($this->writeListeners[$key])) {
124124+ $event = $this->writeEvents[$key];
125125+ \event_del($event);
126126+ \event_free($event);
127127+128128+ unset(
129129+ $this->writeEvents[$key],
130130+ $this->writeListeners[$key]
131131+ );
132132+ }
133133+ }
134134+135135+ public function addTimer($interval, $callback)
136136+ {
137137+ $timer = new Timer($interval, $callback, false);
138138+139139+ $this->scheduleTimer($timer);
140140+141141+ return $timer;
142142+ }
143143+144144+ public function addPeriodicTimer($interval, $callback)
145145+ {
146146+ $timer = new Timer($interval, $callback, true);
147147+148148+ $this->scheduleTimer($timer);
149149+150150+ return $timer;
151151+ }
152152+153153+ public function cancelTimer(TimerInterface $timer)
154154+ {
155155+ if ($this->timerEvents->contains($timer)) {
156156+ $event = $this->timerEvents[$timer];
157157+ \event_del($event);
158158+ \event_free($event);
159159+160160+ $this->timerEvents->detach($timer);
161161+ }
162162+ }
163163+164164+ public function futureTick($listener)
165165+ {
166166+ $this->futureTickQueue->add($listener);
167167+ }
168168+169169+ public function addSignal($signal, $listener)
170170+ {
171171+ $this->signals->add($signal, $listener);
172172+173173+ if (!isset($this->signalEvents[$signal])) {
174174+ $this->signalEvents[$signal] = \event_new();
175175+ \event_set($this->signalEvents[$signal], $signal, \EV_PERSIST | \EV_SIGNAL, array($this->signals, 'call'));
176176+ \event_base_set($this->signalEvents[$signal], $this->eventBase);
177177+ \event_add($this->signalEvents[$signal]);
178178+ }
179179+ }
180180+181181+ public function removeSignal($signal, $listener)
182182+ {
183183+ $this->signals->remove($signal, $listener);
184184+185185+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
186186+ \event_del($this->signalEvents[$signal]);
187187+ \event_free($this->signalEvents[$signal]);
188188+ unset($this->signalEvents[$signal]);
189189+ }
190190+ }
191191+192192+ public function run()
193193+ {
194194+ $this->running = true;
195195+196196+ while ($this->running) {
197197+ $this->futureTickQueue->tick();
198198+199199+ $flags = \EVLOOP_ONCE;
200200+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
201201+ $flags |= \EVLOOP_NONBLOCK;
202202+ } elseif (!$this->readEvents && !$this->writeEvents && !$this->timerEvents->count() && $this->signals->isEmpty()) {
203203+ break;
204204+ }
205205+206206+ \event_base_loop($this->eventBase, $flags);
207207+ }
208208+ }
209209+210210+ public function stop()
211211+ {
212212+ $this->running = false;
213213+ }
214214+215215+ /**
216216+ * Schedule a timer for execution.
217217+ *
218218+ * @param TimerInterface $timer
219219+ */
220220+ private function scheduleTimer(TimerInterface $timer)
221221+ {
222222+ $this->timerEvents[$timer] = $event = \event_timer_new();
223223+224224+ \event_timer_set($event, $this->timerCallback, $timer);
225225+ \event_base_set($event, $this->eventBase);
226226+ \event_add($event, $timer->getInterval() * self::MICROSECONDS_PER_SECOND);
227227+ }
228228+229229+ /**
230230+ * Create a callback used as the target of timer events.
231231+ *
232232+ * A reference is kept to the callback for the lifetime of the loop
233233+ * to prevent "Cannot destroy active lambda function" fatal error from
234234+ * the event extension.
235235+ */
236236+ private function createTimerCallback()
237237+ {
238238+ $that = $this;
239239+ $timers = $this->timerEvents;
240240+ $this->timerCallback = function ($_, $__, $timer) use ($timers, $that) {
241241+ \call_user_func($timer->getCallback(), $timer);
242242+243243+ // Timer already cancelled ...
244244+ if (!$timers->contains($timer)) {
245245+ return;
246246+ }
247247+248248+ // Reschedule periodic timers ...
249249+ if ($timer->isPeriodic()) {
250250+ \event_add(
251251+ $timers[$timer],
252252+ $timer->getInterval() * ExtLibeventLoop::MICROSECONDS_PER_SECOND
253253+ );
254254+255255+ // Clean-up one shot timers ...
256256+ } else {
257257+ $that->cancelTimer($timer);
258258+ }
259259+ };
260260+ }
261261+262262+ /**
263263+ * Create a callback used as the target of stream events.
264264+ *
265265+ * A reference is kept to the callback for the lifetime of the loop
266266+ * to prevent "Cannot destroy active lambda function" fatal error from
267267+ * the event extension.
268268+ */
269269+ private function createStreamCallback()
270270+ {
271271+ $read =& $this->readListeners;
272272+ $write =& $this->writeListeners;
273273+ $this->streamCallback = function ($stream, $flags) use (&$read, &$write) {
274274+ $key = (int) $stream;
275275+276276+ if (\EV_READ === (\EV_READ & $flags) && isset($read[$key])) {
277277+ \call_user_func($read[$key], $stream);
278278+ }
279279+280280+ if (\EV_WRITE === (\EV_WRITE & $flags) && isset($write[$key])) {
281281+ \call_user_func($write[$key], $stream);
282282+ }
283283+ };
284284+ }
285285+}
+342
vendor/react/event-loop/src/ExtUvLoop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+use React\EventLoop\Tick\FutureTickQueue;
66+use React\EventLoop\Timer\Timer;
77+use SplObjectStorage;
88+99+/**
1010+ * An `ext-uv` based event loop.
1111+ *
1212+ * This loop uses the [`uv` PECL extension](https://pecl.php.net/package/uv),
1313+ * that provides an interface to `libuv` library.
1414+ * `libuv` itself supports a number of system-specific backends (epoll, kqueue).
1515+ *
1616+ * This loop is known to work with PHP 7+.
1717+ *
1818+ * @see https://github.com/bwoebi/php-uv
1919+ */
2020+final class ExtUvLoop implements LoopInterface
2121+{
2222+ private $uv;
2323+ private $futureTickQueue;
2424+ private $timers;
2525+ private $streamEvents = array();
2626+ private $readStreams = array();
2727+ private $writeStreams = array();
2828+ private $running;
2929+ private $signals;
3030+ private $signalEvents = array();
3131+ private $streamListener;
3232+3333+ public function __construct()
3434+ {
3535+ if (!\function_exists('uv_loop_new')) {
3636+ throw new \BadMethodCallException('Cannot create LibUvLoop, ext-uv extension missing');
3737+ }
3838+3939+ $this->uv = \uv_loop_new();
4040+ $this->futureTickQueue = new FutureTickQueue();
4141+ $this->timers = new SplObjectStorage();
4242+ $this->streamListener = $this->createStreamListener();
4343+ $this->signals = new SignalsHandler();
4444+ }
4545+4646+ /**
4747+ * Returns the underlying ext-uv event loop. (Internal ReactPHP use only.)
4848+ *
4949+ * @internal
5050+ *
5151+ * @return resource
5252+ */
5353+ public function getUvLoop()
5454+ {
5555+ return $this->uv;
5656+ }
5757+5858+ /**
5959+ * {@inheritdoc}
6060+ */
6161+ public function addReadStream($stream, $listener)
6262+ {
6363+ if (isset($this->readStreams[(int) $stream])) {
6464+ return;
6565+ }
6666+6767+ $this->readStreams[(int) $stream] = $listener;
6868+ $this->addStream($stream);
6969+ }
7070+7171+ /**
7272+ * {@inheritdoc}
7373+ */
7474+ public function addWriteStream($stream, $listener)
7575+ {
7676+ if (isset($this->writeStreams[(int) $stream])) {
7777+ return;
7878+ }
7979+8080+ $this->writeStreams[(int) $stream] = $listener;
8181+ $this->addStream($stream);
8282+ }
8383+8484+ /**
8585+ * {@inheritdoc}
8686+ */
8787+ public function removeReadStream($stream)
8888+ {
8989+ if (!isset($this->streamEvents[(int) $stream])) {
9090+ return;
9191+ }
9292+9393+ unset($this->readStreams[(int) $stream]);
9494+ $this->removeStream($stream);
9595+ }
9696+9797+ /**
9898+ * {@inheritdoc}
9999+ */
100100+ public function removeWriteStream($stream)
101101+ {
102102+ if (!isset($this->streamEvents[(int) $stream])) {
103103+ return;
104104+ }
105105+106106+ unset($this->writeStreams[(int) $stream]);
107107+ $this->removeStream($stream);
108108+ }
109109+110110+ /**
111111+ * {@inheritdoc}
112112+ */
113113+ public function addTimer($interval, $callback)
114114+ {
115115+ $timer = new Timer($interval, $callback, false);
116116+117117+ $that = $this;
118118+ $timers = $this->timers;
119119+ $callback = function () use ($timer, $timers, $that) {
120120+ \call_user_func($timer->getCallback(), $timer);
121121+122122+ if ($timers->contains($timer)) {
123123+ $that->cancelTimer($timer);
124124+ }
125125+ };
126126+127127+ $event = \uv_timer_init($this->uv);
128128+ $this->timers->attach($timer, $event);
129129+ \uv_timer_start(
130130+ $event,
131131+ $this->convertFloatSecondsToMilliseconds($interval),
132132+ 0,
133133+ $callback
134134+ );
135135+136136+ return $timer;
137137+ }
138138+139139+ /**
140140+ * {@inheritdoc}
141141+ */
142142+ public function addPeriodicTimer($interval, $callback)
143143+ {
144144+ $timer = new Timer($interval, $callback, true);
145145+146146+ $callback = function () use ($timer) {
147147+ \call_user_func($timer->getCallback(), $timer);
148148+ };
149149+150150+ $interval = $this->convertFloatSecondsToMilliseconds($interval);
151151+ $event = \uv_timer_init($this->uv);
152152+ $this->timers->attach($timer, $event);
153153+ \uv_timer_start(
154154+ $event,
155155+ $interval,
156156+ (int) $interval === 0 ? 1 : $interval,
157157+ $callback
158158+ );
159159+160160+ return $timer;
161161+ }
162162+163163+ /**
164164+ * {@inheritdoc}
165165+ */
166166+ public function cancelTimer(TimerInterface $timer)
167167+ {
168168+ if (isset($this->timers[$timer])) {
169169+ @\uv_timer_stop($this->timers[$timer]);
170170+ $this->timers->detach($timer);
171171+ }
172172+ }
173173+174174+ /**
175175+ * {@inheritdoc}
176176+ */
177177+ public function futureTick($listener)
178178+ {
179179+ $this->futureTickQueue->add($listener);
180180+ }
181181+182182+ public function addSignal($signal, $listener)
183183+ {
184184+ $this->signals->add($signal, $listener);
185185+186186+ if (!isset($this->signalEvents[$signal])) {
187187+ $signals = $this->signals;
188188+ $this->signalEvents[$signal] = \uv_signal_init($this->uv);
189189+ \uv_signal_start($this->signalEvents[$signal], function () use ($signals, $signal) {
190190+ $signals->call($signal);
191191+ }, $signal);
192192+ }
193193+ }
194194+195195+ public function removeSignal($signal, $listener)
196196+ {
197197+ $this->signals->remove($signal, $listener);
198198+199199+ if (isset($this->signalEvents[$signal]) && $this->signals->count($signal) === 0) {
200200+ \uv_signal_stop($this->signalEvents[$signal]);
201201+ unset($this->signalEvents[$signal]);
202202+ }
203203+ }
204204+205205+ /**
206206+ * {@inheritdoc}
207207+ */
208208+ public function run()
209209+ {
210210+ $this->running = true;
211211+212212+ while ($this->running) {
213213+ $this->futureTickQueue->tick();
214214+215215+ $hasPendingCallbacks = !$this->futureTickQueue->isEmpty();
216216+ $wasJustStopped = !$this->running;
217217+ $nothingLeftToDo = !$this->readStreams
218218+ && !$this->writeStreams
219219+ && !$this->timers->count()
220220+ && $this->signals->isEmpty();
221221+222222+ // Use UV::RUN_ONCE when there are only I/O events active in the loop and block until one of those triggers,
223223+ // otherwise use UV::RUN_NOWAIT.
224224+ // @link http://docs.libuv.org/en/v1.x/loop.html#c.uv_run
225225+ $flags = \UV::RUN_ONCE;
226226+ if ($wasJustStopped || $hasPendingCallbacks) {
227227+ $flags = \UV::RUN_NOWAIT;
228228+ } elseif ($nothingLeftToDo) {
229229+ break;
230230+ }
231231+232232+ \uv_run($this->uv, $flags);
233233+ }
234234+ }
235235+236236+ /**
237237+ * {@inheritdoc}
238238+ */
239239+ public function stop()
240240+ {
241241+ $this->running = false;
242242+ }
243243+244244+ private function addStream($stream)
245245+ {
246246+ if (!isset($this->streamEvents[(int) $stream])) {
247247+ $this->streamEvents[(int)$stream] = \uv_poll_init_socket($this->uv, $stream);
248248+ }
249249+250250+ if ($this->streamEvents[(int) $stream] !== false) {
251251+ $this->pollStream($stream);
252252+ }
253253+ }
254254+255255+ private function removeStream($stream)
256256+ {
257257+ if (!isset($this->streamEvents[(int) $stream])) {
258258+ return;
259259+ }
260260+261261+ if (!isset($this->readStreams[(int) $stream])
262262+ && !isset($this->writeStreams[(int) $stream])) {
263263+ \uv_poll_stop($this->streamEvents[(int) $stream]);
264264+ \uv_close($this->streamEvents[(int) $stream]);
265265+ unset($this->streamEvents[(int) $stream]);
266266+ return;
267267+ }
268268+269269+ $this->pollStream($stream);
270270+ }
271271+272272+ private function pollStream($stream)
273273+ {
274274+ if (!isset($this->streamEvents[(int) $stream])) {
275275+ return;
276276+ }
277277+278278+ $flags = 0;
279279+ if (isset($this->readStreams[(int) $stream])) {
280280+ $flags |= \UV::READABLE;
281281+ }
282282+283283+ if (isset($this->writeStreams[(int) $stream])) {
284284+ $flags |= \UV::WRITABLE;
285285+ }
286286+287287+ \uv_poll_start($this->streamEvents[(int) $stream], $flags, $this->streamListener);
288288+ }
289289+290290+ /**
291291+ * Create a stream listener
292292+ *
293293+ * @return callable Returns a callback
294294+ */
295295+ private function createStreamListener()
296296+ {
297297+ $callback = function ($event, $status, $events, $stream) {
298298+ // libuv automatically stops polling on error, re-enable polling to match other loop implementations
299299+ if ($status !== 0) {
300300+ $this->pollStream($stream);
301301+302302+ // libuv may report no events on error, but this should still invoke stream listeners to report closed connections
303303+ // re-enable both readable and writable, correct listeners will be checked below anyway
304304+ if ($events === 0) {
305305+ $events = \UV::READABLE | \UV::WRITABLE;
306306+ }
307307+ }
308308+309309+ if (isset($this->readStreams[(int) $stream]) && ($events & \UV::READABLE)) {
310310+ \call_user_func($this->readStreams[(int) $stream], $stream);
311311+ }
312312+313313+ if (isset($this->writeStreams[(int) $stream]) && ($events & \UV::WRITABLE)) {
314314+ \call_user_func($this->writeStreams[(int) $stream], $stream);
315315+ }
316316+ };
317317+318318+ return $callback;
319319+ }
320320+321321+ /**
322322+ * @param float $interval
323323+ * @return int
324324+ */
325325+ private function convertFloatSecondsToMilliseconds($interval)
326326+ {
327327+ if ($interval < 0) {
328328+ return 0;
329329+ }
330330+331331+ $maxValue = (int) (\PHP_INT_MAX / 1000);
332332+ $intInterval = (int) $interval;
333333+334334+ if (($intInterval <= 0 && $interval > 1) || $intInterval >= $maxValue) {
335335+ throw new \InvalidArgumentException(
336336+ "Interval overflow, value must be lower than '{$maxValue}', but '{$interval}' passed."
337337+ );
338338+ }
339339+340340+ return (int) \floor($interval * 1000);
341341+ }
342342+}
+75
vendor/react/event-loop/src/Factory.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+/**
66+ * [Deprecated] The `Factory` class exists as a convenient way to pick the best available event loop implementation.
77+ *
88+ * @deprecated 1.2.0 See Loop instead.
99+ * @see Loop
1010+ */
1111+final class Factory
1212+{
1313+ /**
1414+ * [Deprecated] Creates a new event loop instance
1515+ *
1616+ * ```php
1717+ * // deprecated
1818+ * $loop = React\EventLoop\Factory::create();
1919+ *
2020+ * // new
2121+ * $loop = React\EventLoop\Loop::get();
2222+ * ```
2323+ *
2424+ * This method always returns an instance implementing `LoopInterface`,
2525+ * the actual event loop implementation is an implementation detail.
2626+ *
2727+ * This method should usually only be called once at the beginning of the program.
2828+ *
2929+ * @deprecated 1.2.0 See Loop::get() instead.
3030+ * @see Loop::get()
3131+ *
3232+ * @return LoopInterface
3333+ */
3434+ public static function create()
3535+ {
3636+ $loop = self::construct();
3737+3838+ Loop::set($loop);
3939+4040+ return $loop;
4141+ }
4242+4343+ /**
4444+ * @internal
4545+ * @return LoopInterface
4646+ */
4747+ private static function construct()
4848+ {
4949+ // @codeCoverageIgnoreStart
5050+ if (\function_exists('uv_loop_new')) {
5151+ // only use ext-uv on PHP 7
5252+ return new ExtUvLoop();
5353+ }
5454+5555+ if (\class_exists('libev\EventLoop', false)) {
5656+ return new ExtLibevLoop();
5757+ }
5858+5959+ if (\class_exists('EvLoop', false)) {
6060+ return new ExtEvLoop();
6161+ }
6262+6363+ if (\class_exists('EventBase', false)) {
6464+ return new ExtEventLoop();
6565+ }
6666+6767+ if (\function_exists('event_base_new') && \PHP_MAJOR_VERSION === 5) {
6868+ // only use ext-libevent on PHP 5 for now
6969+ return new ExtLibeventLoop();
7070+ }
7171+7272+ return new StreamSelectLoop();
7373+ // @codeCoverageIgnoreEnd
7474+ }
7575+}
+266
vendor/react/event-loop/src/Loop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+/**
66+ * The `Loop` class exists as a convenient way to get the currently relevant loop
77+ */
88+final class Loop
99+{
1010+ /**
1111+ * @var ?LoopInterface
1212+ */
1313+ private static $instance;
1414+1515+ /** @var bool */
1616+ private static $stopped = false;
1717+1818+ /**
1919+ * Returns the event loop.
2020+ * When no loop is set, it will call the factory to create one.
2121+ *
2222+ * This method always returns an instance implementing `LoopInterface`,
2323+ * the actual event loop implementation is an implementation detail.
2424+ *
2525+ * This method is the preferred way to get the event loop and using
2626+ * Factory::create has been deprecated.
2727+ *
2828+ * @return LoopInterface
2929+ */
3030+ public static function get()
3131+ {
3232+ if (self::$instance instanceof LoopInterface) {
3333+ return self::$instance;
3434+ }
3535+3636+ self::$instance = $loop = Factory::create();
3737+3838+ // Automatically run loop at end of program, unless already started or stopped explicitly.
3939+ // This is tested using child processes, so coverage is actually 100%, see BinTest.
4040+ // @codeCoverageIgnoreStart
4141+ $hasRun = false;
4242+ $loop->futureTick(function () use (&$hasRun) {
4343+ $hasRun = true;
4444+ });
4545+4646+ $stopped =& self::$stopped;
4747+ register_shutdown_function(function () use ($loop, &$hasRun, &$stopped) {
4848+ // Don't run if we're coming from a fatal error (uncaught exception).
4949+ $error = error_get_last();
5050+ if ((isset($error['type']) ? $error['type'] : 0) & (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) {
5151+ return;
5252+ }
5353+5454+ if (!$hasRun && !$stopped) {
5555+ $loop->run();
5656+ }
5757+ });
5858+ // @codeCoverageIgnoreEnd
5959+6060+ return self::$instance;
6161+ }
6262+6363+ /**
6464+ * Internal undocumented method, behavior might change or throw in the
6565+ * future. Use with caution and at your own risk.
6666+ *
6767+ * @internal
6868+ * @return void
6969+ */
7070+ public static function set(LoopInterface $loop)
7171+ {
7272+ self::$instance = $loop;
7373+ }
7474+7575+ /**
7676+ * [Advanced] Register a listener to be notified when a stream is ready to read.
7777+ *
7878+ * @param resource $stream
7979+ * @param callable $listener
8080+ * @return void
8181+ * @throws \Exception
8282+ * @see LoopInterface::addReadStream()
8383+ */
8484+ public static function addReadStream($stream, $listener)
8585+ {
8686+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
8787+ if (self::$instance === null) {
8888+ self::get();
8989+ }
9090+ self::$instance->addReadStream($stream, $listener);
9191+ }
9292+9393+ /**
9494+ * [Advanced] Register a listener to be notified when a stream is ready to write.
9595+ *
9696+ * @param resource $stream
9797+ * @param callable $listener
9898+ * @return void
9999+ * @throws \Exception
100100+ * @see LoopInterface::addWriteStream()
101101+ */
102102+ public static function addWriteStream($stream, $listener)
103103+ {
104104+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
105105+ if (self::$instance === null) {
106106+ self::get();
107107+ }
108108+ self::$instance->addWriteStream($stream, $listener);
109109+ }
110110+111111+ /**
112112+ * Remove the read event listener for the given stream.
113113+ *
114114+ * @param resource $stream
115115+ * @return void
116116+ * @see LoopInterface::removeReadStream()
117117+ */
118118+ public static function removeReadStream($stream)
119119+ {
120120+ if (self::$instance !== null) {
121121+ self::$instance->removeReadStream($stream);
122122+ }
123123+ }
124124+125125+ /**
126126+ * Remove the write event listener for the given stream.
127127+ *
128128+ * @param resource $stream
129129+ * @return void
130130+ * @see LoopInterface::removeWriteStream()
131131+ */
132132+ public static function removeWriteStream($stream)
133133+ {
134134+ if (self::$instance !== null) {
135135+ self::$instance->removeWriteStream($stream);
136136+ }
137137+ }
138138+139139+ /**
140140+ * Enqueue a callback to be invoked once after the given interval.
141141+ *
142142+ * @param float $interval
143143+ * @param callable $callback
144144+ * @return TimerInterface
145145+ * @see LoopInterface::addTimer()
146146+ */
147147+ public static function addTimer($interval, $callback)
148148+ {
149149+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
150150+ if (self::$instance === null) {
151151+ self::get();
152152+ }
153153+ return self::$instance->addTimer($interval, $callback);
154154+ }
155155+156156+ /**
157157+ * Enqueue a callback to be invoked repeatedly after the given interval.
158158+ *
159159+ * @param float $interval
160160+ * @param callable $callback
161161+ * @return TimerInterface
162162+ * @see LoopInterface::addPeriodicTimer()
163163+ */
164164+ public static function addPeriodicTimer($interval, $callback)
165165+ {
166166+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
167167+ if (self::$instance === null) {
168168+ self::get();
169169+ }
170170+ return self::$instance->addPeriodicTimer($interval, $callback);
171171+ }
172172+173173+ /**
174174+ * Cancel a pending timer.
175175+ *
176176+ * @param TimerInterface $timer
177177+ * @return void
178178+ * @see LoopInterface::cancelTimer()
179179+ */
180180+ public static function cancelTimer(TimerInterface $timer)
181181+ {
182182+ if (self::$instance !== null) {
183183+ self::$instance->cancelTimer($timer);
184184+ }
185185+ }
186186+187187+ /**
188188+ * Schedule a callback to be invoked on a future tick of the event loop.
189189+ *
190190+ * @param callable $listener
191191+ * @return void
192192+ * @see LoopInterface::futureTick()
193193+ */
194194+ public static function futureTick($listener)
195195+ {
196196+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
197197+ if (self::$instance === null) {
198198+ self::get();
199199+ }
200200+201201+ self::$instance->futureTick($listener);
202202+ }
203203+204204+ /**
205205+ * Register a listener to be notified when a signal has been caught by this process.
206206+ *
207207+ * @param int $signal
208208+ * @param callable $listener
209209+ * @return void
210210+ * @see LoopInterface::addSignal()
211211+ */
212212+ public static function addSignal($signal, $listener)
213213+ {
214214+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
215215+ if (self::$instance === null) {
216216+ self::get();
217217+ }
218218+219219+ self::$instance->addSignal($signal, $listener);
220220+ }
221221+222222+ /**
223223+ * Removes a previously added signal listener.
224224+ *
225225+ * @param int $signal
226226+ * @param callable $listener
227227+ * @return void
228228+ * @see LoopInterface::removeSignal()
229229+ */
230230+ public static function removeSignal($signal, $listener)
231231+ {
232232+ if (self::$instance !== null) {
233233+ self::$instance->removeSignal($signal, $listener);
234234+ }
235235+ }
236236+237237+ /**
238238+ * Run the event loop until there are no more tasks to perform.
239239+ *
240240+ * @return void
241241+ * @see LoopInterface::run()
242242+ */
243243+ public static function run()
244244+ {
245245+ // create loop instance on demand (legacy PHP < 7 doesn't like ternaries in method calls)
246246+ if (self::$instance === null) {
247247+ self::get();
248248+ }
249249+250250+ self::$instance->run();
251251+ }
252252+253253+ /**
254254+ * Instruct a running event loop to stop.
255255+ *
256256+ * @return void
257257+ * @see LoopInterface::stop()
258258+ */
259259+ public static function stop()
260260+ {
261261+ self::$stopped = true;
262262+ if (self::$instance !== null) {
263263+ self::$instance->stop();
264264+ }
265265+ }
266266+}
+472
vendor/react/event-loop/src/LoopInterface.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+interface LoopInterface
66+{
77+ /**
88+ * [Advanced] Register a listener to be notified when a stream is ready to read.
99+ *
1010+ * Note that this low-level API is considered advanced usage.
1111+ * Most use cases should probably use the higher-level
1212+ * [readable Stream API](https://github.com/reactphp/stream#readablestreaminterface)
1313+ * instead.
1414+ *
1515+ * The first parameter MUST be a valid stream resource that supports
1616+ * checking whether it is ready to read by this loop implementation.
1717+ * A single stream resource MUST NOT be added more than once.
1818+ * Instead, either call [`removeReadStream()`](#removereadstream) first or
1919+ * react to this event with a single listener and then dispatch from this
2020+ * listener. This method MAY throw an `Exception` if the given resource type
2121+ * is not supported by this loop implementation.
2222+ *
2323+ * The second parameter MUST be a listener callback function that accepts
2424+ * the stream resource as its only parameter.
2525+ * If you don't use the stream resource inside your listener callback function
2626+ * you MAY use a function which has no parameters at all.
2727+ *
2828+ * The listener callback function MUST NOT throw an `Exception`.
2929+ * The return value of the listener callback function will be ignored and has
3030+ * no effect, so for performance reasons you're recommended to not return
3131+ * any excessive data structures.
3232+ *
3333+ * If you want to access any variables within your callback function, you
3434+ * can bind arbitrary data to a callback closure like this:
3535+ *
3636+ * ```php
3737+ * $loop->addReadStream($stream, function ($stream) use ($name) {
3838+ * echo $name . ' said: ' . fread($stream);
3939+ * });
4040+ * ```
4141+ *
4242+ * See also [example #11](examples).
4343+ *
4444+ * You can invoke [`removeReadStream()`](#removereadstream) to remove the
4545+ * read event listener for this stream.
4646+ *
4747+ * The execution order of listeners when multiple streams become ready at
4848+ * the same time is not guaranteed.
4949+ *
5050+ * @param resource $stream The PHP stream resource to check.
5151+ * @param callable $listener Invoked when the stream is ready.
5252+ * @throws \Exception if the given resource type is not supported by this loop implementation
5353+ * @see self::removeReadStream()
5454+ */
5555+ public function addReadStream($stream, $listener);
5656+5757+ /**
5858+ * [Advanced] Register a listener to be notified when a stream is ready to write.
5959+ *
6060+ * Note that this low-level API is considered advanced usage.
6161+ * Most use cases should probably use the higher-level
6262+ * [writable Stream API](https://github.com/reactphp/stream#writablestreaminterface)
6363+ * instead.
6464+ *
6565+ * The first parameter MUST be a valid stream resource that supports
6666+ * checking whether it is ready to write by this loop implementation.
6767+ * A single stream resource MUST NOT be added more than once.
6868+ * Instead, either call [`removeWriteStream()`](#removewritestream) first or
6969+ * react to this event with a single listener and then dispatch from this
7070+ * listener. This method MAY throw an `Exception` if the given resource type
7171+ * is not supported by this loop implementation.
7272+ *
7373+ * The second parameter MUST be a listener callback function that accepts
7474+ * the stream resource as its only parameter.
7575+ * If you don't use the stream resource inside your listener callback function
7676+ * you MAY use a function which has no parameters at all.
7777+ *
7878+ * The listener callback function MUST NOT throw an `Exception`.
7979+ * The return value of the listener callback function will be ignored and has
8080+ * no effect, so for performance reasons you're recommended to not return
8181+ * any excessive data structures.
8282+ *
8383+ * If you want to access any variables within your callback function, you
8484+ * can bind arbitrary data to a callback closure like this:
8585+ *
8686+ * ```php
8787+ * $loop->addWriteStream($stream, function ($stream) use ($name) {
8888+ * fwrite($stream, 'Hello ' . $name);
8989+ * });
9090+ * ```
9191+ *
9292+ * See also [example #12](examples).
9393+ *
9494+ * You can invoke [`removeWriteStream()`](#removewritestream) to remove the
9595+ * write event listener for this stream.
9696+ *
9797+ * The execution order of listeners when multiple streams become ready at
9898+ * the same time is not guaranteed.
9999+ *
100100+ * Some event loop implementations are known to only trigger the listener if
101101+ * the stream *becomes* readable (edge-triggered) and may not trigger if the
102102+ * stream has already been readable from the beginning.
103103+ * This also implies that a stream may not be recognized as readable when data
104104+ * is still left in PHP's internal stream buffers.
105105+ * As such, it's recommended to use `stream_set_read_buffer($stream, 0);`
106106+ * to disable PHP's internal read buffer in this case.
107107+ *
108108+ * @param resource $stream The PHP stream resource to check.
109109+ * @param callable $listener Invoked when the stream is ready.
110110+ * @throws \Exception if the given resource type is not supported by this loop implementation
111111+ * @see self::removeWriteStream()
112112+ */
113113+ public function addWriteStream($stream, $listener);
114114+115115+ /**
116116+ * Remove the read event listener for the given stream.
117117+ *
118118+ * Removing a stream from the loop that has already been removed or trying
119119+ * to remove a stream that was never added or is invalid has no effect.
120120+ *
121121+ * @param resource $stream The PHP stream resource.
122122+ */
123123+ public function removeReadStream($stream);
124124+125125+ /**
126126+ * Remove the write event listener for the given stream.
127127+ *
128128+ * Removing a stream from the loop that has already been removed or trying
129129+ * to remove a stream that was never added or is invalid has no effect.
130130+ *
131131+ * @param resource $stream The PHP stream resource.
132132+ */
133133+ public function removeWriteStream($stream);
134134+135135+ /**
136136+ * Enqueue a callback to be invoked once after the given interval.
137137+ *
138138+ * The second parameter MUST be a timer callback function that accepts
139139+ * the timer instance as its only parameter.
140140+ * If you don't use the timer instance inside your timer callback function
141141+ * you MAY use a function which has no parameters at all.
142142+ *
143143+ * The timer callback function MUST NOT throw an `Exception`.
144144+ * The return value of the timer callback function will be ignored and has
145145+ * no effect, so for performance reasons you're recommended to not return
146146+ * any excessive data structures.
147147+ *
148148+ * This method returns a timer instance. The same timer instance will also be
149149+ * passed into the timer callback function as described above.
150150+ * You can invoke [`cancelTimer`](#canceltimer) to cancel a pending timer.
151151+ * Unlike [`addPeriodicTimer()`](#addperiodictimer), this method will ensure
152152+ * the callback will be invoked only once after the given interval.
153153+ *
154154+ * ```php
155155+ * $loop->addTimer(0.8, function () {
156156+ * echo 'world!' . PHP_EOL;
157157+ * });
158158+ *
159159+ * $loop->addTimer(0.3, function () {
160160+ * echo 'hello ';
161161+ * });
162162+ * ```
163163+ *
164164+ * See also [example #1](examples).
165165+ *
166166+ * If you want to access any variables within your callback function, you
167167+ * can bind arbitrary data to a callback closure like this:
168168+ *
169169+ * ```php
170170+ * function hello($name, LoopInterface $loop)
171171+ * {
172172+ * $loop->addTimer(1.0, function () use ($name) {
173173+ * echo "hello $name\n";
174174+ * });
175175+ * }
176176+ *
177177+ * hello('Tester', $loop);
178178+ * ```
179179+ *
180180+ * This interface does not enforce any particular timer resolution, so
181181+ * special care may have to be taken if you rely on very high precision with
182182+ * millisecond accuracy or below. Event loop implementations SHOULD work on
183183+ * a best effort basis and SHOULD provide at least millisecond accuracy
184184+ * unless otherwise noted. Many existing event loop implementations are
185185+ * known to provide microsecond accuracy, but it's generally not recommended
186186+ * to rely on this high precision.
187187+ *
188188+ * Similarly, the execution order of timers scheduled to execute at the
189189+ * same time (within its possible accuracy) is not guaranteed.
190190+ *
191191+ * This interface suggests that event loop implementations SHOULD use a
192192+ * monotonic time source if available. Given that a monotonic time source is
193193+ * only available as of PHP 7.3 by default, event loop implementations MAY
194194+ * fall back to using wall-clock time.
195195+ * While this does not affect many common use cases, this is an important
196196+ * distinction for programs that rely on a high time precision or on systems
197197+ * that are subject to discontinuous time adjustments (time jumps).
198198+ * This means that if you schedule a timer to trigger in 30s and then adjust
199199+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
200200+ * See also [event loop implementations](#loop-implementations) for more details.
201201+ *
202202+ * @param int|float $interval The number of seconds to wait before execution.
203203+ * @param callable $callback The callback to invoke.
204204+ *
205205+ * @return TimerInterface
206206+ */
207207+ public function addTimer($interval, $callback);
208208+209209+ /**
210210+ * Enqueue a callback to be invoked repeatedly after the given interval.
211211+ *
212212+ * The second parameter MUST be a timer callback function that accepts
213213+ * the timer instance as its only parameter.
214214+ * If you don't use the timer instance inside your timer callback function
215215+ * you MAY use a function which has no parameters at all.
216216+ *
217217+ * The timer callback function MUST NOT throw an `Exception`.
218218+ * The return value of the timer callback function will be ignored and has
219219+ * no effect, so for performance reasons you're recommended to not return
220220+ * any excessive data structures.
221221+ *
222222+ * This method returns a timer instance. The same timer instance will also be
223223+ * passed into the timer callback function as described above.
224224+ * Unlike [`addTimer()`](#addtimer), this method will ensure the callback
225225+ * will be invoked infinitely after the given interval or until you invoke
226226+ * [`cancelTimer`](#canceltimer).
227227+ *
228228+ * ```php
229229+ * $timer = $loop->addPeriodicTimer(0.1, function () {
230230+ * echo 'tick!' . PHP_EOL;
231231+ * });
232232+ *
233233+ * $loop->addTimer(1.0, function () use ($loop, $timer) {
234234+ * $loop->cancelTimer($timer);
235235+ * echo 'Done' . PHP_EOL;
236236+ * });
237237+ * ```
238238+ *
239239+ * See also [example #2](examples).
240240+ *
241241+ * If you want to limit the number of executions, you can bind
242242+ * arbitrary data to a callback closure like this:
243243+ *
244244+ * ```php
245245+ * function hello($name, LoopInterface $loop)
246246+ * {
247247+ * $n = 3;
248248+ * $loop->addPeriodicTimer(1.0, function ($timer) use ($name, $loop, &$n) {
249249+ * if ($n > 0) {
250250+ * --$n;
251251+ * echo "hello $name\n";
252252+ * } else {
253253+ * $loop->cancelTimer($timer);
254254+ * }
255255+ * });
256256+ * }
257257+ *
258258+ * hello('Tester', $loop);
259259+ * ```
260260+ *
261261+ * This interface does not enforce any particular timer resolution, so
262262+ * special care may have to be taken if you rely on very high precision with
263263+ * millisecond accuracy or below. Event loop implementations SHOULD work on
264264+ * a best effort basis and SHOULD provide at least millisecond accuracy
265265+ * unless otherwise noted. Many existing event loop implementations are
266266+ * known to provide microsecond accuracy, but it's generally not recommended
267267+ * to rely on this high precision.
268268+ *
269269+ * Similarly, the execution order of timers scheduled to execute at the
270270+ * same time (within its possible accuracy) is not guaranteed.
271271+ *
272272+ * This interface suggests that event loop implementations SHOULD use a
273273+ * monotonic time source if available. Given that a monotonic time source is
274274+ * only available as of PHP 7.3 by default, event loop implementations MAY
275275+ * fall back to using wall-clock time.
276276+ * While this does not affect many common use cases, this is an important
277277+ * distinction for programs that rely on a high time precision or on systems
278278+ * that are subject to discontinuous time adjustments (time jumps).
279279+ * This means that if you schedule a timer to trigger in 30s and then adjust
280280+ * your system time forward by 20s, the timer SHOULD still trigger in 30s.
281281+ * See also [event loop implementations](#loop-implementations) for more details.
282282+ *
283283+ * Additionally, periodic timers may be subject to timer drift due to
284284+ * re-scheduling after each invocation. As such, it's generally not
285285+ * recommended to rely on this for high precision intervals with millisecond
286286+ * accuracy or below.
287287+ *
288288+ * @param int|float $interval The number of seconds to wait before execution.
289289+ * @param callable $callback The callback to invoke.
290290+ *
291291+ * @return TimerInterface
292292+ */
293293+ public function addPeriodicTimer($interval, $callback);
294294+295295+ /**
296296+ * Cancel a pending timer.
297297+ *
298298+ * See also [`addPeriodicTimer()`](#addperiodictimer) and [example #2](examples).
299299+ *
300300+ * Calling this method on a timer instance that has not been added to this
301301+ * loop instance or on a timer that has already been cancelled has no effect.
302302+ *
303303+ * @param TimerInterface $timer The timer to cancel.
304304+ *
305305+ * @return void
306306+ */
307307+ public function cancelTimer(TimerInterface $timer);
308308+309309+ /**
310310+ * Schedule a callback to be invoked on a future tick of the event loop.
311311+ *
312312+ * This works very much similar to timers with an interval of zero seconds,
313313+ * but does not require the overhead of scheduling a timer queue.
314314+ *
315315+ * The tick callback function MUST be able to accept zero parameters.
316316+ *
317317+ * The tick callback function MUST NOT throw an `Exception`.
318318+ * The return value of the tick callback function will be ignored and has
319319+ * no effect, so for performance reasons you're recommended to not return
320320+ * any excessive data structures.
321321+ *
322322+ * If you want to access any variables within your callback function, you
323323+ * can bind arbitrary data to a callback closure like this:
324324+ *
325325+ * ```php
326326+ * function hello($name, LoopInterface $loop)
327327+ * {
328328+ * $loop->futureTick(function () use ($name) {
329329+ * echo "hello $name\n";
330330+ * });
331331+ * }
332332+ *
333333+ * hello('Tester', $loop);
334334+ * ```
335335+ *
336336+ * Unlike timers, tick callbacks are guaranteed to be executed in the order
337337+ * they are enqueued.
338338+ * Also, once a callback is enqueued, there's no way to cancel this operation.
339339+ *
340340+ * This is often used to break down bigger tasks into smaller steps (a form
341341+ * of cooperative multitasking).
342342+ *
343343+ * ```php
344344+ * $loop->futureTick(function () {
345345+ * echo 'b';
346346+ * });
347347+ * $loop->futureTick(function () {
348348+ * echo 'c';
349349+ * });
350350+ * echo 'a';
351351+ * ```
352352+ *
353353+ * See also [example #3](examples).
354354+ *
355355+ * @param callable $listener The callback to invoke.
356356+ *
357357+ * @return void
358358+ */
359359+ public function futureTick($listener);
360360+361361+ /**
362362+ * Register a listener to be notified when a signal has been caught by this process.
363363+ *
364364+ * This is useful to catch user interrupt signals or shutdown signals from
365365+ * tools like `supervisor` or `systemd`.
366366+ *
367367+ * The second parameter MUST be a listener callback function that accepts
368368+ * the signal as its only parameter.
369369+ * If you don't use the signal inside your listener callback function
370370+ * you MAY use a function which has no parameters at all.
371371+ *
372372+ * The listener callback function MUST NOT throw an `Exception`.
373373+ * The return value of the listener callback function will be ignored and has
374374+ * no effect, so for performance reasons you're recommended to not return
375375+ * any excessive data structures.
376376+ *
377377+ * ```php
378378+ * $loop->addSignal(SIGINT, function (int $signal) {
379379+ * echo 'Caught user interrupt signal' . PHP_EOL;
380380+ * });
381381+ * ```
382382+ *
383383+ * See also [example #4](examples).
384384+ *
385385+ * Signaling is only available on Unix-like platforms, Windows isn't
386386+ * supported due to operating system limitations.
387387+ * This method may throw a `BadMethodCallException` if signals aren't
388388+ * supported on this platform, for example when required extensions are
389389+ * missing.
390390+ *
391391+ * **Note: A listener can only be added once to the same signal, any
392392+ * attempts to add it more than once will be ignored.**
393393+ *
394394+ * @param int $signal
395395+ * @param callable $listener
396396+ *
397397+ * @throws \BadMethodCallException when signals aren't supported on this
398398+ * platform, for example when required extensions are missing.
399399+ *
400400+ * @return void
401401+ */
402402+ public function addSignal($signal, $listener);
403403+404404+ /**
405405+ * Removes a previously added signal listener.
406406+ *
407407+ * ```php
408408+ * $loop->removeSignal(SIGINT, $listener);
409409+ * ```
410410+ *
411411+ * Any attempts to remove listeners that aren't registered will be ignored.
412412+ *
413413+ * @param int $signal
414414+ * @param callable $listener
415415+ *
416416+ * @return void
417417+ */
418418+ public function removeSignal($signal, $listener);
419419+420420+ /**
421421+ * Run the event loop until there are no more tasks to perform.
422422+ *
423423+ * For many applications, this method is the only directly visible
424424+ * invocation on the event loop.
425425+ * As a rule of thumb, it is usually recommended to attach everything to the
426426+ * same loop instance and then run the loop once at the bottom end of the
427427+ * application.
428428+ *
429429+ * ```php
430430+ * $loop->run();
431431+ * ```
432432+ *
433433+ * This method will keep the loop running until there are no more tasks
434434+ * to perform. In other words: This method will block until the last
435435+ * timer, stream and/or signal has been removed.
436436+ *
437437+ * Likewise, it is imperative to ensure the application actually invokes
438438+ * this method once. Adding listeners to the loop and missing to actually
439439+ * run it will result in the application exiting without actually waiting
440440+ * for any of the attached listeners.
441441+ *
442442+ * This method MUST NOT be called while the loop is already running.
443443+ * This method MAY be called more than once after it has explicitly been
444444+ * [`stop()`ped](#stop) or after it automatically stopped because it
445445+ * previously did no longer have anything to do.
446446+ *
447447+ * @return void
448448+ */
449449+ public function run();
450450+451451+ /**
452452+ * Instruct a running event loop to stop.
453453+ *
454454+ * This method is considered advanced usage and should be used with care.
455455+ * As a rule of thumb, it is usually recommended to let the loop stop
456456+ * only automatically when it no longer has anything to do.
457457+ *
458458+ * This method can be used to explicitly instruct the event loop to stop:
459459+ *
460460+ * ```php
461461+ * $loop->addTimer(3.0, function () use ($loop) {
462462+ * $loop->stop();
463463+ * });
464464+ * ```
465465+ *
466466+ * Calling this method on a loop instance that is not currently running or
467467+ * on a loop instance that has already been stopped has no effect.
468468+ *
469469+ * @return void
470470+ */
471471+ public function stop();
472472+}
+63
vendor/react/event-loop/src/SignalsHandler.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+/**
66+ * @internal
77+ */
88+final class SignalsHandler
99+{
1010+ private $signals = array();
1111+1212+ public function add($signal, $listener)
1313+ {
1414+ if (!isset($this->signals[$signal])) {
1515+ $this->signals[$signal] = array();
1616+ }
1717+1818+ if (\in_array($listener, $this->signals[$signal])) {
1919+ return;
2020+ }
2121+2222+ $this->signals[$signal][] = $listener;
2323+ }
2424+2525+ public function remove($signal, $listener)
2626+ {
2727+ if (!isset($this->signals[$signal])) {
2828+ return;
2929+ }
3030+3131+ $index = \array_search($listener, $this->signals[$signal], true);
3232+ unset($this->signals[$signal][$index]);
3333+3434+ if (isset($this->signals[$signal]) && \count($this->signals[$signal]) === 0) {
3535+ unset($this->signals[$signal]);
3636+ }
3737+ }
3838+3939+ public function call($signal)
4040+ {
4141+ if (!isset($this->signals[$signal])) {
4242+ return;
4343+ }
4444+4545+ foreach ($this->signals[$signal] as $listener) {
4646+ \call_user_func($listener, $signal);
4747+ }
4848+ }
4949+5050+ public function count($signal)
5151+ {
5252+ if (!isset($this->signals[$signal])) {
5353+ return 0;
5454+ }
5555+5656+ return \count($this->signals[$signal]);
5757+ }
5858+5959+ public function isEmpty()
6060+ {
6161+ return !$this->signals;
6262+ }
6363+}
+330
vendor/react/event-loop/src/StreamSelectLoop.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+use React\EventLoop\Tick\FutureTickQueue;
66+use React\EventLoop\Timer\Timer;
77+use React\EventLoop\Timer\Timers;
88+99+/**
1010+ * A `stream_select()` based event loop.
1111+ *
1212+ * This uses the [`stream_select()`](https://www.php.net/manual/en/function.stream-select.php)
1313+ * function and is the only implementation that works out of the box with PHP.
1414+ *
1515+ * This event loop works out of the box on PHP 5.4 through PHP 8+ and HHVM.
1616+ * This means that no installation is required and this library works on all
1717+ * platforms and supported PHP versions.
1818+ * Accordingly, the [`Loop` class](#loop) and the deprecated [`Factory`](#factory)
1919+ * will use this event loop by default if you do not install any of the event loop
2020+ * extensions listed below.
2121+ *
2222+ * Under the hood, it does a simple `select` system call.
2323+ * This system call is limited to the maximum file descriptor number of
2424+ * `FD_SETSIZE` (platform dependent, commonly 1024) and scales with `O(m)`
2525+ * (`m` being the maximum file descriptor number passed).
2626+ * This means that you may run into issues when handling thousands of streams
2727+ * concurrently and you may want to look into using one of the alternative
2828+ * event loop implementations listed below in this case.
2929+ * If your use case is among the many common use cases that involve handling only
3030+ * dozens or a few hundred streams at once, then this event loop implementation
3131+ * performs really well.
3232+ *
3333+ * If you want to use signal handling (see also [`addSignal()`](#addsignal) below),
3434+ * this event loop implementation requires `ext-pcntl`.
3535+ * This extension is only available for Unix-like platforms and does not support
3636+ * Windows.
3737+ * It is commonly installed as part of many PHP distributions.
3838+ * If this extension is missing (or you're running on Windows), signal handling is
3939+ * not supported and throws a `BadMethodCallException` instead.
4040+ *
4141+ * This event loop is known to rely on wall-clock time to schedule future timers
4242+ * when using any version before PHP 7.3, because a monotonic time source is
4343+ * only available as of PHP 7.3 (`hrtime()`).
4444+ * While this does not affect many common use cases, this is an important
4545+ * distinction for programs that rely on a high time precision or on systems
4646+ * that are subject to discontinuous time adjustments (time jumps).
4747+ * This means that if you schedule a timer to trigger in 30s on PHP < 7.3 and
4848+ * then adjust your system time forward by 20s, the timer may trigger in 10s.
4949+ * See also [`addTimer()`](#addtimer) for more details.
5050+ *
5151+ * @link https://www.php.net/manual/en/function.stream-select.php
5252+ */
5353+final class StreamSelectLoop implements LoopInterface
5454+{
5555+ /** @internal */
5656+ const MICROSECONDS_PER_SECOND = 1000000;
5757+5858+ private $futureTickQueue;
5959+ private $timers;
6060+ private $readStreams = array();
6161+ private $readListeners = array();
6262+ private $writeStreams = array();
6363+ private $writeListeners = array();
6464+ private $running;
6565+ private $pcntl = false;
6666+ private $pcntlPoll = false;
6767+ private $signals;
6868+6969+ public function __construct()
7070+ {
7171+ $this->futureTickQueue = new FutureTickQueue();
7272+ $this->timers = new Timers();
7373+ $this->pcntl = \function_exists('pcntl_signal') && \function_exists('pcntl_signal_dispatch');
7474+ $this->pcntlPoll = $this->pcntl && !\function_exists('pcntl_async_signals');
7575+ $this->signals = new SignalsHandler();
7676+7777+ // prefer async signals if available (PHP 7.1+) or fall back to dispatching on each tick
7878+ if ($this->pcntl && !$this->pcntlPoll) {
7979+ \pcntl_async_signals(true);
8080+ }
8181+ }
8282+8383+ public function addReadStream($stream, $listener)
8484+ {
8585+ $key = (int) $stream;
8686+8787+ if (!isset($this->readStreams[$key])) {
8888+ $this->readStreams[$key] = $stream;
8989+ $this->readListeners[$key] = $listener;
9090+ }
9191+ }
9292+9393+ public function addWriteStream($stream, $listener)
9494+ {
9595+ $key = (int) $stream;
9696+9797+ if (!isset($this->writeStreams[$key])) {
9898+ $this->writeStreams[$key] = $stream;
9999+ $this->writeListeners[$key] = $listener;
100100+ }
101101+ }
102102+103103+ public function removeReadStream($stream)
104104+ {
105105+ $key = (int) $stream;
106106+107107+ unset(
108108+ $this->readStreams[$key],
109109+ $this->readListeners[$key]
110110+ );
111111+ }
112112+113113+ public function removeWriteStream($stream)
114114+ {
115115+ $key = (int) $stream;
116116+117117+ unset(
118118+ $this->writeStreams[$key],
119119+ $this->writeListeners[$key]
120120+ );
121121+ }
122122+123123+ public function addTimer($interval, $callback)
124124+ {
125125+ $timer = new Timer($interval, $callback, false);
126126+127127+ $this->timers->add($timer);
128128+129129+ return $timer;
130130+ }
131131+132132+ public function addPeriodicTimer($interval, $callback)
133133+ {
134134+ $timer = new Timer($interval, $callback, true);
135135+136136+ $this->timers->add($timer);
137137+138138+ return $timer;
139139+ }
140140+141141+ public function cancelTimer(TimerInterface $timer)
142142+ {
143143+ $this->timers->cancel($timer);
144144+ }
145145+146146+ public function futureTick($listener)
147147+ {
148148+ $this->futureTickQueue->add($listener);
149149+ }
150150+151151+ public function addSignal($signal, $listener)
152152+ {
153153+ if ($this->pcntl === false) {
154154+ throw new \BadMethodCallException('Event loop feature "signals" isn\'t supported by the "StreamSelectLoop"');
155155+ }
156156+157157+ $first = $this->signals->count($signal) === 0;
158158+ $this->signals->add($signal, $listener);
159159+160160+ if ($first) {
161161+ \pcntl_signal($signal, array($this->signals, 'call'));
162162+ }
163163+ }
164164+165165+ public function removeSignal($signal, $listener)
166166+ {
167167+ if (!$this->signals->count($signal)) {
168168+ return;
169169+ }
170170+171171+ $this->signals->remove($signal, $listener);
172172+173173+ if ($this->signals->count($signal) === 0) {
174174+ \pcntl_signal($signal, \SIG_DFL);
175175+ }
176176+ }
177177+178178+ public function run()
179179+ {
180180+ $this->running = true;
181181+182182+ while ($this->running) {
183183+ $this->futureTickQueue->tick();
184184+185185+ $this->timers->tick();
186186+187187+ // Future-tick queue has pending callbacks ...
188188+ if (!$this->running || !$this->futureTickQueue->isEmpty()) {
189189+ $timeout = 0;
190190+191191+ // There is a pending timer, only block until it is due ...
192192+ } elseif ($scheduledAt = $this->timers->getFirst()) {
193193+ $timeout = $scheduledAt - $this->timers->getTime();
194194+ if ($timeout < 0) {
195195+ $timeout = 0;
196196+ } else {
197197+ // Convert float seconds to int microseconds.
198198+ // Ensure we do not exceed maximum integer size, which may
199199+ // cause the loop to tick once every ~35min on 32bit systems.
200200+ $timeout *= self::MICROSECONDS_PER_SECOND;
201201+ $timeout = $timeout > \PHP_INT_MAX ? \PHP_INT_MAX : (int)$timeout;
202202+ }
203203+204204+ // The only possible event is stream or signal activity, so wait forever ...
205205+ } elseif ($this->readStreams || $this->writeStreams || !$this->signals->isEmpty()) {
206206+ $timeout = null;
207207+208208+ // There's nothing left to do ...
209209+ } else {
210210+ break;
211211+ }
212212+213213+ $this->waitForStreamActivity($timeout);
214214+ }
215215+ }
216216+217217+ public function stop()
218218+ {
219219+ $this->running = false;
220220+ }
221221+222222+ /**
223223+ * Wait/check for stream activity, or until the next timer is due.
224224+ *
225225+ * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever.
226226+ */
227227+ private function waitForStreamActivity($timeout)
228228+ {
229229+ $read = $this->readStreams;
230230+ $write = $this->writeStreams;
231231+232232+ $available = $this->streamSelect($read, $write, $timeout);
233233+ if ($this->pcntlPoll) {
234234+ \pcntl_signal_dispatch();
235235+ }
236236+ if (false === $available) {
237237+ // if a system call has been interrupted,
238238+ // we cannot rely on it's outcome
239239+ return;
240240+ }
241241+242242+ foreach ($read as $stream) {
243243+ $key = (int) $stream;
244244+245245+ if (isset($this->readListeners[$key])) {
246246+ \call_user_func($this->readListeners[$key], $stream);
247247+ }
248248+ }
249249+250250+ foreach ($write as $stream) {
251251+ $key = (int) $stream;
252252+253253+ if (isset($this->writeListeners[$key])) {
254254+ \call_user_func($this->writeListeners[$key], $stream);
255255+ }
256256+ }
257257+ }
258258+259259+ /**
260260+ * Emulate a stream_select() implementation that does not break when passed
261261+ * empty stream arrays.
262262+ *
263263+ * @param array $read An array of read streams to select upon.
264264+ * @param array $write An array of write streams to select upon.
265265+ * @param int|null $timeout Activity timeout in microseconds, or null to wait forever.
266266+ *
267267+ * @return int|false The total number of streams that are ready for read/write.
268268+ * Can return false if stream_select() is interrupted by a signal.
269269+ */
270270+ private function streamSelect(array &$read, array &$write, $timeout)
271271+ {
272272+ if ($read || $write) {
273273+ // We do not usually use or expose the `exceptfds` parameter passed to the underlying `select`.
274274+ // However, Windows does not report failed connection attempts in `writefds` passed to `select` like most other platforms.
275275+ // Instead, it uses `writefds` only for successful connection attempts and `exceptfds` for failed connection attempts.
276276+ // We work around this by adding all sockets that look like a pending connection attempt to `exceptfds` automatically on Windows and merge it back later.
277277+ // This ensures the public API matches other loop implementations across all platforms (see also test suite or rather test matrix).
278278+ // Lacking better APIs, every write-only socket that has not yet read any data is assumed to be in a pending connection attempt state.
279279+ // @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select
280280+ $except = null;
281281+ if (\DIRECTORY_SEPARATOR === '\\') {
282282+ $except = array();
283283+ foreach ($write as $key => $socket) {
284284+ if (!isset($read[$key]) && @\ftell($socket) === 0) {
285285+ $except[$key] = $socket;
286286+ }
287287+ }
288288+ }
289289+290290+ /** @var ?callable $previous */
291291+ $previous = \set_error_handler(function ($errno, $errstr) use (&$previous) {
292292+ // suppress warnings that occur when `stream_select()` is interrupted by a signal
293293+ // PHP defines `EINTR` through `ext-sockets` or `ext-pcntl`, otherwise use common default (Linux & Mac)
294294+ $eintr = \defined('SOCKET_EINTR') ? \SOCKET_EINTR : (\defined('PCNTL_EINTR') ? \PCNTL_EINTR : 4);
295295+ if ($errno === \E_WARNING && \strpos($errstr, '[' . $eintr .']: ') !== false) {
296296+ return;
297297+ }
298298+299299+ // forward any other error to registered error handler or print warning
300300+ return ($previous !== null) ? \call_user_func_array($previous, \func_get_args()) : false;
301301+ });
302302+303303+ try {
304304+ $ret = \stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout);
305305+ \restore_error_handler();
306306+ } catch (\Throwable $e) { // @codeCoverageIgnoreStart
307307+ \restore_error_handler();
308308+ throw $e;
309309+ } catch (\Exception $e) {
310310+ \restore_error_handler();
311311+ throw $e;
312312+ } // @codeCoverageIgnoreEnd
313313+314314+ if ($except) {
315315+ $write = \array_merge($write, $except);
316316+ }
317317+ return $ret;
318318+ }
319319+320320+ if ($timeout > 0) {
321321+ \usleep($timeout);
322322+ } elseif ($timeout === null) {
323323+ // wait forever (we only reach this if we're only awaiting signals)
324324+ // this may be interrupted and return earlier when a signal is received
325325+ \sleep(PHP_INT_MAX);
326326+ }
327327+328328+ return 0;
329329+ }
330330+}
···11+<?php
22+33+namespace React\EventLoop\Tick;
44+55+use SplQueue;
66+77+/**
88+ * A tick queue implementation that can hold multiple callback functions
99+ *
1010+ * This class should only be used internally, see LoopInterface instead.
1111+ *
1212+ * @see LoopInterface
1313+ * @internal
1414+ */
1515+final class FutureTickQueue
1616+{
1717+ private $queue;
1818+1919+ public function __construct()
2020+ {
2121+ $this->queue = new SplQueue();
2222+ }
2323+2424+ /**
2525+ * Add a callback to be invoked on a future tick of the event loop.
2626+ *
2727+ * Callbacks are guaranteed to be executed in the order they are enqueued.
2828+ *
2929+ * @param callable $listener The callback to invoke.
3030+ */
3131+ public function add($listener)
3232+ {
3333+ $this->queue->enqueue($listener);
3434+ }
3535+3636+ /**
3737+ * Flush the callback queue.
3838+ */
3939+ public function tick()
4040+ {
4141+ // Only invoke as many callbacks as were on the queue when tick() was called.
4242+ $count = $this->queue->count();
4343+4444+ while ($count--) {
4545+ \call_user_func(
4646+ $this->queue->dequeue()
4747+ );
4848+ }
4949+ }
5050+5151+ /**
5252+ * Check if the next tick queue is empty.
5353+ *
5454+ * @return boolean
5555+ */
5656+ public function isEmpty()
5757+ {
5858+ return $this->queue->isEmpty();
5959+ }
6060+}
+55
vendor/react/event-loop/src/Timer/Timer.php
···11+<?php
22+33+namespace React\EventLoop\Timer;
44+55+use React\EventLoop\TimerInterface;
66+77+/**
88+ * The actual connection implementation for TimerInterface
99+ *
1010+ * This class should only be used internally, see TimerInterface instead.
1111+ *
1212+ * @see TimerInterface
1313+ * @internal
1414+ */
1515+final class Timer implements TimerInterface
1616+{
1717+ const MIN_INTERVAL = 0.000001;
1818+1919+ private $interval;
2020+ private $callback;
2121+ private $periodic;
2222+2323+ /**
2424+ * Constructor initializes the fields of the Timer
2525+ *
2626+ * @param float $interval The interval after which this timer will execute, in seconds
2727+ * @param callable $callback The callback that will be executed when this timer elapses
2828+ * @param bool $periodic Whether the time is periodic
2929+ */
3030+ public function __construct($interval, $callback, $periodic = false)
3131+ {
3232+ if ($interval < self::MIN_INTERVAL) {
3333+ $interval = self::MIN_INTERVAL;
3434+ }
3535+3636+ $this->interval = (float) $interval;
3737+ $this->callback = $callback;
3838+ $this->periodic = (bool) $periodic;
3939+ }
4040+4141+ public function getInterval()
4242+ {
4343+ return $this->interval;
4444+ }
4545+4646+ public function getCallback()
4747+ {
4848+ return $this->callback;
4949+ }
5050+5151+ public function isPeriodic()
5252+ {
5353+ return $this->periodic;
5454+ }
5555+}
+113
vendor/react/event-loop/src/Timer/Timers.php
···11+<?php
22+33+namespace React\EventLoop\Timer;
44+55+use React\EventLoop\TimerInterface;
66+77+/**
88+ * A scheduler implementation that can hold multiple timer instances
99+ *
1010+ * This class should only be used internally, see TimerInterface instead.
1111+ *
1212+ * @see TimerInterface
1313+ * @internal
1414+ */
1515+final class Timers
1616+{
1717+ private $time;
1818+ private $timers = array();
1919+ private $schedule = array();
2020+ private $sorted = true;
2121+ private $useHighResolution;
2222+2323+ public function __construct()
2424+ {
2525+ // prefer high-resolution timer, available as of PHP 7.3+
2626+ $this->useHighResolution = \function_exists('hrtime');
2727+ }
2828+2929+ public function updateTime()
3030+ {
3131+ return $this->time = $this->useHighResolution ? \hrtime(true) * 1e-9 : \microtime(true);
3232+ }
3333+3434+ public function getTime()
3535+ {
3636+ return $this->time ?: $this->updateTime();
3737+ }
3838+3939+ public function add(TimerInterface $timer)
4040+ {
4141+ $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
4242+ $this->timers[$id] = $timer;
4343+ $this->schedule[$id] = $timer->getInterval() + $this->updateTime();
4444+ $this->sorted = false;
4545+ }
4646+4747+ public function contains(TimerInterface $timer)
4848+ {
4949+ $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
5050+ return isset($this->timers[$id]);
5151+ }
5252+5353+ public function cancel(TimerInterface $timer)
5454+ {
5555+ $id = \PHP_VERSION_ID < 70200 ? \spl_object_hash($timer) : \spl_object_id($timer);
5656+ unset($this->timers[$id], $this->schedule[$id]);
5757+ }
5858+5959+ public function getFirst()
6060+ {
6161+ // ensure timers are sorted to simply accessing next (first) one
6262+ if (!$this->sorted) {
6363+ $this->sorted = true;
6464+ \asort($this->schedule);
6565+ }
6666+6767+ return \reset($this->schedule);
6868+ }
6969+7070+ public function isEmpty()
7171+ {
7272+ return \count($this->timers) === 0;
7373+ }
7474+7575+ public function tick()
7676+ {
7777+ // hot path: skip timers if nothing is scheduled
7878+ if (!$this->schedule) {
7979+ return;
8080+ }
8181+8282+ // ensure timers are sorted so we can execute in order
8383+ if (!$this->sorted) {
8484+ $this->sorted = true;
8585+ \asort($this->schedule);
8686+ }
8787+8888+ $time = $this->updateTime();
8989+9090+ foreach ($this->schedule as $id => $scheduled) {
9191+ // schedule is ordered, so loop until first timer that is not scheduled for execution now
9292+ if ($scheduled >= $time) {
9393+ break;
9494+ }
9595+9696+ // skip any timers that are removed while we process the current schedule
9797+ if (!isset($this->schedule[$id]) || $this->schedule[$id] !== $scheduled) {
9898+ continue;
9999+ }
100100+101101+ $timer = $this->timers[$id];
102102+ \call_user_func($timer->getCallback(), $timer);
103103+104104+ // re-schedule if this is a periodic timer and it has not been cancelled explicitly already
105105+ if ($timer->isPeriodic() && isset($this->timers[$id])) {
106106+ $this->schedule[$id] = $timer->getInterval() + $time;
107107+ $this->sorted = false;
108108+ } else {
109109+ unset($this->timers[$id], $this->schedule[$id]);
110110+ }
111111+ }
112112+ }
113113+}
+27
vendor/react/event-loop/src/TimerInterface.php
···11+<?php
22+33+namespace React\EventLoop;
44+55+interface TimerInterface
66+{
77+ /**
88+ * Get the interval after which this timer will execute, in seconds
99+ *
1010+ * @return float
1111+ */
1212+ public function getInterval();
1313+1414+ /**
1515+ * Get the callback that will be executed when this timer elapses
1616+ *
1717+ * @return callable
1818+ */
1919+ public function getCallback();
2020+2121+ /**
2222+ * Determine whether the time is periodic
2323+ *
2424+ * @return bool
2525+ */
2626+ public function isPeriodic();
2727+}
+156
vendor/react/promise/CHANGELOG.md
···11+# Changelog
22+33+## 3.2.0 (2024-05-24)
44+55+* Feature: Improve PHP 8.4+ support by avoiding implicitly nullable type declarations.
66+ (#260 by @Ayesh)
77+88+* Feature: Include previous exceptions when reporting unhandled promise rejections.
99+ (#262 by @clue)
1010+1111+* Update test suite to improve PHP 8.4+ support.
1212+ (#261 by @SimonFrings)
1313+1414+## 3.1.0 (2023-11-16)
1515+1616+* Feature: Full PHP 8.3 compatibility.
1717+ (#255 by @clue)
1818+1919+* Feature: Describe all callable arguments with types for `Promise` and `Deferred`.
2020+ (#253 by @clue)
2121+2222+* Update test suite and minor documentation improvements.
2323+ (#251 by @ondrejmirtes and #250 by @SQKo)
2424+2525+## 3.0.0 (2023-07-11)
2626+2727+A major new feature release, see [**release announcement**](https://clue.engineering/2023/announcing-reactphp-promise-v3).
2828+2929+* We'd like to emphasize that this component is production ready and battle-tested.
3030+ We plan to support all long-term support (LTS) releases for at least 24 months,
3131+ so you have a rock-solid foundation to build on top of.
3232+3333+* The v3 release will be the way forward for this package. However, we will still
3434+ actively support v2 and v1 to provide a smooth upgrade path for those not yet
3535+ on the latest versions.
3636+3737+This update involves some major new features and a minor BC break over the
3838+`v2.0.0` release. We've tried hard to avoid BC breaks where possible and
3939+minimize impact otherwise. We expect that most consumers of this package will be
4040+affected by BC breaks, but updating should take no longer than a few minutes.
4141+See below for more details:
4242+4343+* BC break: PHP 8.1+ recommended, PHP 7.1+ required.
4444+ (#138 and #149 by @WyriHaximus)
4545+4646+* Feature / BC break: The `PromiseInterface` now includes the functionality of the old ~~`ExtendedPromiseInterface`~~ and ~~`CancellablePromiseInterface`~~.
4747+ Each promise now always includes the `then()`, `catch()`, `finally()` and `cancel()` methods.
4848+ The new `catch()` and `finally()` methods replace the deprecated ~~`otherwise()`~~ and ~~`always()`~~ methods which continue to exist for BC reasons.
4949+ The old ~~`ExtendedPromiseInterface`~~ and ~~`CancellablePromiseInterface`~~ are no longer needed and have been removed as a consequence.
5050+ (#75 by @jsor and #208 by @clue and @WyriHaximus)
5151+5252+ ```php
5353+ // old (multiple interfaces may or may not be implemented)
5454+ assert($promise instanceof PromiseInterface);
5555+ assert(method_exists($promise, 'then'));
5656+ if ($promise instanceof ExtendedPromiseInterface) { assert(method_exists($promise, 'otherwise')); }
5757+ if ($promise instanceof ExtendedPromiseInterface) { assert(method_exists($promise, 'always')); }
5858+ if ($promise instanceof CancellablePromiseInterface) { assert(method_exists($promise, 'cancel')); }
5959+6060+ // new (single PromiseInterface with all methods)
6161+ assert($promise instanceof PromiseInterface);
6262+ assert(method_exists($promise, 'then'));
6363+ assert(method_exists($promise, 'catch'));
6464+ assert(method_exists($promise, 'finally'));
6565+ assert(method_exists($promise, 'cancel'));
6666+ ```
6767+6868+* Feature / BC break: Improve type safety of promises. Require `mixed` fulfillment value argument and `Throwable` (or `Exception`) as rejection reason.
6969+ Add PHPStan template types to ensure strict types for `resolve(T $value): PromiseInterface<T>` and `reject(Throwable $reason): PromiseInterface<never>`.
7070+ It is no longer possible to resolve a promise without a value (use `null` instead) or reject a promise without a reason (use `Throwable` instead).
7171+ (#93, #141 and #142 by @jsor, #138, #149 and #247 by @WyriHaximus and #213 and #246 by @clue)
7272+7373+ ```php
7474+ // old (arguments used to be optional)
7575+ $promise = resolve();
7676+ $promise = reject();
7777+7878+ // new (already supported before)
7979+ $promise = resolve(null);
8080+ $promise = reject(new RuntimeException());
8181+ ```
8282+8383+* Feature / BC break: Report all unhandled rejections by default and remove ~~`done()`~~ method.
8484+ Add new `set_rejection_handler()` function to set the global rejection handler for unhandled promise rejections.
8585+ (#248, #249 and #224 by @clue)
8686+8787+ ```php
8888+ // Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
8989+ reject(new RuntimeException('Unhandled'));
9090+ ```
9191+9292+* BC break: Remove all deprecated APIs and reduce API surface.
9393+ Remove ~~`some()`~~, ~~`map()`~~, ~~`reduce()`~~ functions, use `any()` and `all()` functions instead.
9494+ Remove internal ~~`FulfilledPromise`~~ and ~~`RejectedPromise`~~ classes, use `resolve()` and `reject()` functions instead.
9595+ Remove legacy promise progress API (deprecated third argument to `then()` method) and deprecated ~~`LazyPromise`~~ class.
9696+ (#32 and #98 by @jsor and #164, #219 and #220 by @clue)
9797+9898+* BC break: Make all classes final to encourage composition over inheritance.
9999+ (#80 by @jsor)
100100+101101+* Feature / BC break: Require `array` (or `iterable`) type for `all()` + `race()` + `any()` functions and bring in line with ES6 specification.
102102+ These functions now require a single argument with a variable number of promises or values as input.
103103+ (#225 by @clue and #35 by @jsor)
104104+105105+* Fix / BC break: Fix `race()` to return a forever pending promise when called with an empty `array` (or `iterable`) and bring in line with ES6 specification.
106106+ (#83 by @jsor and #225 by @clue)
107107+108108+* Minor performance improvements by initializing `Deferred` in the constructor and avoiding `call_user_func()` calls.
109109+ (#151 by @WyriHaximus and #171 by @Kubo2)
110110+111111+* Minor documentation improvements.
112112+ (#110 by @seregazhuk, #132 by @CharlotteDunois, #145 by @danielecr, #178 by @WyriHaximus, #189 by @srdante, #212 by @clue, #214, #239 and #243 by @SimonFrings and #231 by @nhedger)
113113+114114+The following changes had to be ported to this release due to our branching
115115+strategy, but also appeared in the [`2.x` branch](https://github.com/reactphp/promise/tree/2.x):
116116+117117+* Feature: Support union types and address deprecation of `ReflectionType::getClass()` (PHP 8+).
118118+ (#197 by @cdosoftei and @SimonFrings)
119119+120120+* Feature: Support intersection types (PHP 8.1+).
121121+ (#209 by @bzikarsky)
122122+123123+* Feature: Support DNS types (PHP 8.2+).
124124+ (#236 by @nhedger)
125125+126126+* Feature: Port all memory improvements from `2.x` to `3.x`.
127127+ (#150 by @clue and @WyriHaximus)
128128+129129+* Fix: Fix checking whether cancellable promise is an object and avoid possible warning.
130130+ (#161 by @smscr)
131131+132132+* Improve performance by prefixing all global functions calls with \ to skip the look up and resolve process and go straight to the global function.
133133+ (#134 by @WyriHaximus)
134134+135135+* Improve test suite, update PHPUnit and PHP versions and add `.gitattributes` to exclude dev files from exports.
136136+ (#107 by @carusogabriel, #148 and #234 by @WyriHaximus, #153 by @reedy, #162, #230 and #240 by @clue, #173, #177, #185 and #199 by @SimonFrings, #193 by @woodongwong and #210 by @bzikarsky)
137137+138138+The following changes were originally planned for this release but later reverted
139139+and are not part of the final release:
140140+141141+* Add iterative callback queue handler to avoid recursion (later removed to improve Fiber support).
142142+ (#28, #82 and #86 by @jsor, #158 by @WyriHaximus and #229 and #238 by @clue)
143143+144144+* Trigger an `E_USER_ERROR` instead of throwing an exception from `done()` (later removed entire `done()` method to globally report unhandled rejections).
145145+ (#97 by @jsor and #224 and #248 by @clue)
146146+147147+* Add type declarations for `some()` (later removed entire `some()` function).
148148+ (#172 by @WyriHaximus and #219 by @clue)
149149+150150+## 2.0.0 (2013-12-10)
151151+152152+See [`2.x` CHANGELOG](https://github.com/reactphp/promise/blob/2.x/CHANGELOG.md) for more details.
153153+154154+## 1.0.0 (2012-11-07)
155155+156156+See [`1.x` CHANGELOG](https://github.com/reactphp/promise/blob/1.x/CHANGELOG.md) for more details.
+24
vendor/react/promise/LICENSE
···11+The MIT License (MIT)
22+33+Copyright (c) 2012 Jan Sorgalla, Christian Lück, Cees-Jan Kiewiet, Chris Boden
44+55+Permission is hereby granted, free of charge, to any person
66+obtaining a copy of this software and associated documentation
77+files (the "Software"), to deal in the Software without
88+restriction, including without limitation the rights to use,
99+copy, modify, merge, publish, distribute, sublicense, and/or sell
1010+copies of the Software, and to permit persons to whom the
1111+Software is furnished to do so, subject to the following
1212+conditions:
1313+1414+The above copyright notice and this permission notice shall be
1515+included in all copies or substantial portions of the Software.
1616+1717+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1818+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
1919+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2020+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
2121+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2222+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2323+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2424+OTHER DEALINGS IN THE SOFTWARE.
+722
vendor/react/promise/README.md
···11+Promise
22+=======
33+44+A lightweight implementation of
55+[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
66+77+[](https://github.com/reactphp/promise/actions)
88+[](https://packagist.org/packages/react/promise)
99+1010+Table of Contents
1111+-----------------
1212+1313+1. [Introduction](#introduction)
1414+2. [Concepts](#concepts)
1515+ * [Deferred](#deferred)
1616+ * [Promise](#promise-1)
1717+3. [API](#api)
1818+ * [Deferred](#deferred-1)
1919+ * [Deferred::promise()](#deferredpromise)
2020+ * [Deferred::resolve()](#deferredresolve)
2121+ * [Deferred::reject()](#deferredreject)
2222+ * [PromiseInterface](#promiseinterface)
2323+ * [PromiseInterface::then()](#promiseinterfacethen)
2424+ * [PromiseInterface::catch()](#promiseinterfacecatch)
2525+ * [PromiseInterface::finally()](#promiseinterfacefinally)
2626+ * [PromiseInterface::cancel()](#promiseinterfacecancel)
2727+ * [~~PromiseInterface::otherwise()~~](#promiseinterfaceotherwise)
2828+ * [~~PromiseInterface::always()~~](#promiseinterfacealways)
2929+ * [Promise](#promise-2)
3030+ * [Functions](#functions)
3131+ * [resolve()](#resolve)
3232+ * [reject()](#reject)
3333+ * [all()](#all)
3434+ * [race()](#race)
3535+ * [any()](#any)
3636+ * [set_rejection_handler()](#set_rejection_handler)
3737+4. [Examples](#examples)
3838+ * [How to use Deferred](#how-to-use-deferred)
3939+ * [How promise forwarding works](#how-promise-forwarding-works)
4040+ * [Resolution forwarding](#resolution-forwarding)
4141+ * [Rejection forwarding](#rejection-forwarding)
4242+ * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding)
4343+5. [Install](#install)
4444+6. [Tests](#tests)
4545+7. [Credits](#credits)
4646+8. [License](#license)
4747+4848+Introduction
4949+------------
5050+5151+Promise is a library implementing
5252+[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP.
5353+5454+It also provides several other useful promise-related concepts, such as joining
5555+multiple promises and mapping and reducing collections of promises.
5656+5757+If you've never heard about promises before,
5858+[read this first](https://gist.github.com/domenic/3889970).
5959+6060+Concepts
6161+--------
6262+6363+### Deferred
6464+6565+A **Deferred** represents a computation or unit of work that may not have
6666+completed yet. Typically (but not always), that computation will be something
6767+that executes asynchronously and completes at some point in the future.
6868+6969+### Promise
7070+7171+While a deferred represents the computation itself, a **Promise** represents
7272+the result of that computation. Thus, each deferred has a promise that acts as
7373+a placeholder for its actual result.
7474+7575+API
7676+---
7777+7878+### Deferred
7979+8080+A deferred represents an operation whose resolution is pending. It has separate
8181+promise and resolver parts.
8282+8383+```php
8484+$deferred = new React\Promise\Deferred();
8585+8686+$promise = $deferred->promise();
8787+8888+$deferred->resolve(mixed $value);
8989+$deferred->reject(\Throwable $reason);
9090+```
9191+9292+The `promise` method returns the promise of the deferred.
9393+9494+The `resolve` and `reject` methods control the state of the deferred.
9595+9696+The constructor of the `Deferred` accepts an optional `$canceller` argument.
9797+See [Promise](#promise-2) for more information.
9898+9999+#### Deferred::promise()
100100+101101+```php
102102+$promise = $deferred->promise();
103103+```
104104+105105+Returns the promise of the deferred, which you can hand out to others while
106106+keeping the authority to modify its state to yourself.
107107+108108+#### Deferred::resolve()
109109+110110+```php
111111+$deferred->resolve(mixed $value);
112112+```
113113+114114+Resolves the promise returned by `promise()`. All consumers are notified by
115115+having `$onFulfilled` (which they registered via `$promise->then()`) called with
116116+`$value`.
117117+118118+If `$value` itself is a promise, the promise will transition to the state of
119119+this promise once it is resolved.
120120+121121+See also the [`resolve()` function](#resolve).
122122+123123+#### Deferred::reject()
124124+125125+```php
126126+$deferred->reject(\Throwable $reason);
127127+```
128128+129129+Rejects the promise returned by `promise()`, signalling that the deferred's
130130+computation failed.
131131+All consumers are notified by having `$onRejected` (which they registered via
132132+`$promise->then()`) called with `$reason`.
133133+134134+See also the [`reject()` function](#reject).
135135+136136+### PromiseInterface
137137+138138+The promise interface provides the common interface for all promise
139139+implementations.
140140+See [Promise](#promise-2) for the only public implementation exposed by this
141141+package.
142142+143143+A promise represents an eventual outcome, which is either fulfillment (success)
144144+and an associated value, or rejection (failure) and an associated reason.
145145+146146+Once in the fulfilled or rejected state, a promise becomes immutable.
147147+Neither its state nor its result (or error) can be modified.
148148+149149+#### PromiseInterface::then()
150150+151151+```php
152152+$transformedPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null);
153153+```
154154+155155+Transforms a promise's value by applying a function to the promise's fulfillment
156156+or rejection value. Returns a new promise for the transformed result.
157157+158158+The `then()` method registers new fulfilled and rejection handlers with a promise
159159+(all parameters are optional):
160160+161161+ * `$onFulfilled` will be invoked once the promise is fulfilled and passed
162162+ the result as the first argument.
163163+ * `$onRejected` will be invoked once the promise is rejected and passed the
164164+ reason as the first argument.
165165+166166+It returns a new promise that will fulfill with the return value of either
167167+`$onFulfilled` or `$onRejected`, whichever is called, or will reject with
168168+the thrown exception if either throws.
169169+170170+A promise makes the following guarantees about handlers registered in
171171+the same call to `then()`:
172172+173173+ 1. Only one of `$onFulfilled` or `$onRejected` will be called,
174174+ never both.
175175+ 2. `$onFulfilled` and `$onRejected` will never be called more
176176+ than once.
177177+178178+#### See also
179179+180180+* [resolve()](#resolve) - Creating a resolved promise
181181+* [reject()](#reject) - Creating a rejected promise
182182+183183+#### PromiseInterface::catch()
184184+185185+```php
186186+$promise->catch(callable $onRejected);
187187+```
188188+189189+Registers a rejection handler for promise. It is a shortcut for:
190190+191191+```php
192192+$promise->then(null, $onRejected);
193193+```
194194+195195+Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
196196+only specific errors.
197197+198198+```php
199199+$promise
200200+ ->catch(function (\RuntimeException $reason) {
201201+ // Only catch \RuntimeException instances
202202+ // All other types of errors will propagate automatically
203203+ })
204204+ ->catch(function (\Throwable $reason) {
205205+ // Catch other errors
206206+ });
207207+```
208208+209209+#### PromiseInterface::finally()
210210+211211+```php
212212+$newPromise = $promise->finally(callable $onFulfilledOrRejected);
213213+```
214214+215215+Allows you to execute "cleanup" type tasks in a promise chain.
216216+217217+It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
218218+when the promise is either fulfilled or rejected.
219219+220220+* If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
221221+ `$newPromise` will fulfill with the same value as `$promise`.
222222+* If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
223223+ rejected promise, `$newPromise` will reject with the thrown exception or
224224+ rejected promise's reason.
225225+* If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
226226+ `$newPromise` will reject with the same reason as `$promise`.
227227+* If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
228228+ rejected promise, `$newPromise` will reject with the thrown exception or
229229+ rejected promise's reason.
230230+231231+`finally()` behaves similarly to the synchronous finally statement. When combined
232232+with `catch()`, `finally()` allows you to write code that is similar to the familiar
233233+synchronous catch/finally pair.
234234+235235+Consider the following synchronous code:
236236+237237+```php
238238+try {
239239+ return doSomething();
240240+} catch (\Throwable $e) {
241241+ return handleError($e);
242242+} finally {
243243+ cleanup();
244244+}
245245+```
246246+247247+Similar asynchronous code (with `doSomething()` that returns a promise) can be
248248+written:
249249+250250+```php
251251+return doSomething()
252252+ ->catch('handleError')
253253+ ->finally('cleanup');
254254+```
255255+256256+#### PromiseInterface::cancel()
257257+258258+``` php
259259+$promise->cancel();
260260+```
261261+262262+The `cancel()` method notifies the creator of the promise that there is no
263263+further interest in the results of the operation.
264264+265265+Once a promise is settled (either fulfilled or rejected), calling `cancel()` on
266266+a promise has no effect.
267267+268268+#### ~~PromiseInterface::otherwise()~~
269269+270270+> Deprecated since v3.0.0, see [`catch()`](#promiseinterfacecatch) instead.
271271+272272+The `otherwise()` method registers a rejection handler for a promise.
273273+274274+This method continues to exist only for BC reasons and to ease upgrading
275275+between versions. It is an alias for:
276276+277277+```php
278278+$promise->catch($onRejected);
279279+```
280280+281281+#### ~~PromiseInterface::always()~~
282282+283283+> Deprecated since v3.0.0, see [`finally()`](#promiseinterfacefinally) instead.
284284+285285+The `always()` method allows you to execute "cleanup" type tasks in a promise chain.
286286+287287+This method continues to exist only for BC reasons and to ease upgrading
288288+between versions. It is an alias for:
289289+290290+```php
291291+$promise->finally($onFulfilledOrRejected);
292292+```
293293+294294+### Promise
295295+296296+Creates a promise whose state is controlled by the functions passed to
297297+`$resolver`.
298298+299299+```php
300300+$resolver = function (callable $resolve, callable $reject) {
301301+ // Do some work, possibly asynchronously, and then
302302+ // resolve or reject.
303303+304304+ $resolve($awesomeResult);
305305+ // or throw new Exception('Promise rejected');
306306+ // or $resolve($anotherPromise);
307307+ // or $reject($nastyError);
308308+};
309309+310310+$canceller = function () {
311311+ // Cancel/abort any running operations like network connections, streams etc.
312312+313313+ // Reject promise by throwing an exception
314314+ throw new Exception('Promise cancelled');
315315+};
316316+317317+$promise = new React\Promise\Promise($resolver, $canceller);
318318+```
319319+320320+The promise constructor receives a resolver function and an optional canceller
321321+function which both will be called with two arguments:
322322+323323+ * `$resolve($value)` - Primary function that seals the fate of the
324324+ returned promise. Accepts either a non-promise value, or another promise.
325325+ When called with a non-promise value, fulfills promise with that value.
326326+ When called with another promise, e.g. `$resolve($otherPromise)`, promise's
327327+ fate will be equivalent to that of `$otherPromise`.
328328+ * `$reject($reason)` - Function that rejects the promise. It is recommended to
329329+ just throw an exception instead of using `$reject()`.
330330+331331+If the resolver or canceller throw an exception, the promise will be rejected
332332+with that thrown exception as the rejection reason.
333333+334334+The resolver function will be called immediately, the canceller function only
335335+once all consumers called the `cancel()` method of the promise.
336336+337337+### Functions
338338+339339+Useful functions for creating and joining collections of promises.
340340+341341+All functions working on promise collections (like `all()`, `race()`,
342342+etc.) support cancellation. This means, if you call `cancel()` on the returned
343343+promise, all promises in the collection are cancelled.
344344+345345+#### resolve()
346346+347347+```php
348348+$promise = React\Promise\resolve(mixed $promiseOrValue);
349349+```
350350+351351+Creates a promise for the supplied `$promiseOrValue`.
352352+353353+If `$promiseOrValue` is a value, it will be the resolution value of the
354354+returned promise.
355355+356356+If `$promiseOrValue` is a thenable (any object that provides a `then()` method),
357357+a trusted promise that follows the state of the thenable is returned.
358358+359359+If `$promiseOrValue` is a promise, it will be returned as is.
360360+361361+The resulting `$promise` implements the [`PromiseInterface`](#promiseinterface)
362362+and can be consumed like any other promise:
363363+364364+```php
365365+$promise = React\Promise\resolve(42);
366366+367367+$promise->then(function (int $result): void {
368368+ var_dump($result);
369369+}, function (\Throwable $e): void {
370370+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
371371+});
372372+```
373373+374374+#### reject()
375375+376376+```php
377377+$promise = React\Promise\reject(\Throwable $reason);
378378+```
379379+380380+Creates a rejected promise for the supplied `$reason`.
381381+382382+Note that the [`\Throwable`](https://www.php.net/manual/en/class.throwable.php) interface introduced in PHP 7 covers
383383+both user land [`\Exception`](https://www.php.net/manual/en/class.exception.php)'s and
384384+[`\Error`](https://www.php.net/manual/en/class.error.php) internal PHP errors. By enforcing `\Throwable` as reason to
385385+reject a promise, any language error or user land exception can be used to reject a promise.
386386+387387+The resulting `$promise` implements the [`PromiseInterface`](#promiseinterface)
388388+and can be consumed like any other promise:
389389+390390+```php
391391+$promise = React\Promise\reject(new RuntimeException('Request failed'));
392392+393393+$promise->then(function (int $result): void {
394394+ var_dump($result);
395395+}, function (\Throwable $e): void {
396396+ echo 'Error: ' . $e->getMessage() . PHP_EOL;
397397+});
398398+```
399399+400400+Note that rejected promises should always be handled similar to how any
401401+exceptions should always be caught in a `try` + `catch` block. If you remove the
402402+last reference to a rejected promise that has not been handled, it will
403403+report an unhandled promise rejection:
404404+405405+```php
406406+function incorrect(): int
407407+{
408408+ $promise = React\Promise\reject(new RuntimeException('Request failed'));
409409+410410+ // Commented out: No rejection handler registered here.
411411+ // $promise->then(null, function (\Throwable $e): void { /* ignore */ });
412412+413413+ // Returning from a function will remove all local variable references, hence why
414414+ // this will report an unhandled promise rejection here.
415415+ return 42;
416416+}
417417+418418+// Calling this function will log an error message plus its stack trace:
419419+// Unhandled promise rejection with RuntimeException: Request failed in example.php:10
420420+incorrect();
421421+```
422422+423423+A rejected promise will be considered "handled" if you catch the rejection
424424+reason with either the [`then()` method](#promiseinterfacethen), the
425425+[`catch()` method](#promiseinterfacecatch), or the
426426+[`finally()` method](#promiseinterfacefinally). Note that each of these methods
427427+return a new promise that may again be rejected if you re-throw an exception.
428428+429429+A rejected promise will also be considered "handled" if you abort the operation
430430+with the [`cancel()` method](#promiseinterfacecancel) (which in turn would
431431+usually reject the promise if it is still pending).
432432+433433+See also the [`set_rejection_handler()` function](#set_rejection_handler).
434434+435435+#### all()
436436+437437+```php
438438+$promise = React\Promise\all(iterable $promisesOrValues);
439439+```
440440+441441+Returns a promise that will resolve only once all the items in
442442+`$promisesOrValues` have resolved. The resolution value of the returned promise
443443+will be an array containing the resolution values of each of the items in
444444+`$promisesOrValues`.
445445+446446+#### race()
447447+448448+```php
449449+$promise = React\Promise\race(iterable $promisesOrValues);
450450+```
451451+452452+Initiates a competitive race that allows one winner. Returns a promise which is
453453+resolved in the same way the first settled promise resolves.
454454+455455+The returned promise will become **infinitely pending** if `$promisesOrValues`
456456+contains 0 items.
457457+458458+#### any()
459459+460460+```php
461461+$promise = React\Promise\any(iterable $promisesOrValues);
462462+```
463463+464464+Returns a promise that will resolve when any one of the items in
465465+`$promisesOrValues` resolves. The resolution value of the returned promise
466466+will be the resolution value of the triggering item.
467467+468468+The returned promise will only reject if *all* items in `$promisesOrValues` are
469469+rejected. The rejection value will be a `React\Promise\Exception\CompositeException`
470470+which holds all rejection reasons. The rejection reasons can be obtained with
471471+`CompositeException::getThrowables()`.
472472+473473+The returned promise will also reject with a `React\Promise\Exception\LengthException`
474474+if `$promisesOrValues` contains 0 items.
475475+476476+#### set_rejection_handler()
477477+478478+```php
479479+React\Promise\set_rejection_handler(?callable $callback): ?callable;
480480+```
481481+482482+Sets the global rejection handler for unhandled promise rejections.
483483+484484+Note that rejected promises should always be handled similar to how any
485485+exceptions should always be caught in a `try` + `catch` block. If you remove
486486+the last reference to a rejected promise that has not been handled, it will
487487+report an unhandled promise rejection. See also the [`reject()` function](#reject)
488488+for more details.
489489+490490+The `?callable $callback` argument MUST be a valid callback function that
491491+accepts a single `Throwable` argument or a `null` value to restore the
492492+default promise rejection handler. The return value of the callback function
493493+will be ignored and has no effect, so you SHOULD return a `void` value. The
494494+callback function MUST NOT throw or the program will be terminated with a
495495+fatal error.
496496+497497+The function returns the previous rejection handler or `null` if using the
498498+default promise rejection handler.
499499+500500+The default promise rejection handler will log an error message plus its stack
501501+trace:
502502+503503+```php
504504+// Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
505505+React\Promise\reject(new RuntimeException('Unhandled'));
506506+```
507507+508508+The promise rejection handler may be used to use customize the log message or
509509+write to custom log targets. As a rule of thumb, this function should only be
510510+used as a last resort and promise rejections are best handled with either the
511511+[`then()` method](#promiseinterfacethen), the
512512+[`catch()` method](#promiseinterfacecatch), or the
513513+[`finally()` method](#promiseinterfacefinally).
514514+See also the [`reject()` function](#reject) for more details.
515515+516516+Examples
517517+--------
518518+519519+### How to use Deferred
520520+521521+```php
522522+function getAwesomeResultPromise()
523523+{
524524+ $deferred = new React\Promise\Deferred();
525525+526526+ // Execute a Node.js-style function using the callback pattern
527527+ computeAwesomeResultAsynchronously(function (\Throwable $error, $result) use ($deferred) {
528528+ if ($error) {
529529+ $deferred->reject($error);
530530+ } else {
531531+ $deferred->resolve($result);
532532+ }
533533+ });
534534+535535+ // Return the promise
536536+ return $deferred->promise();
537537+}
538538+539539+getAwesomeResultPromise()
540540+ ->then(
541541+ function ($value) {
542542+ // Deferred resolved, do something with $value
543543+ },
544544+ function (\Throwable $reason) {
545545+ // Deferred rejected, do something with $reason
546546+ }
547547+ );
548548+```
549549+550550+### How promise forwarding works
551551+552552+A few simple examples to show how the mechanics of Promises/A forwarding works.
553553+These examples are contrived, of course, and in real usage, promise chains will
554554+typically be spread across several function calls, or even several levels of
555555+your application architecture.
556556+557557+#### Resolution forwarding
558558+559559+Resolved promises forward resolution values to the next promise.
560560+The first promise, `$deferred->promise()`, will resolve with the value passed
561561+to `$deferred->resolve()` below.
562562+563563+Each call to `then()` returns a new promise that will resolve with the return
564564+value of the previous handler. This creates a promise "pipeline".
565565+566566+```php
567567+$deferred = new React\Promise\Deferred();
568568+569569+$deferred->promise()
570570+ ->then(function ($x) {
571571+ // $x will be the value passed to $deferred->resolve() below
572572+ // and returns a *new promise* for $x + 1
573573+ return $x + 1;
574574+ })
575575+ ->then(function ($x) {
576576+ // $x === 2
577577+ // This handler receives the return value of the
578578+ // previous handler.
579579+ return $x + 1;
580580+ })
581581+ ->then(function ($x) {
582582+ // $x === 3
583583+ // This handler receives the return value of the
584584+ // previous handler.
585585+ return $x + 1;
586586+ })
587587+ ->then(function ($x) {
588588+ // $x === 4
589589+ // This handler receives the return value of the
590590+ // previous handler.
591591+ echo 'Resolve ' . $x;
592592+ });
593593+594594+$deferred->resolve(1); // Prints "Resolve 4"
595595+```
596596+597597+#### Rejection forwarding
598598+599599+Rejected promises behave similarly, and also work similarly to try/catch:
600600+When you catch an exception, you must rethrow for it to propagate.
601601+602602+Similarly, when you handle a rejected promise, to propagate the rejection,
603603+"rethrow" it by either returning a rejected promise, or actually throwing
604604+(since promise translates thrown exceptions into rejections)
605605+606606+```php
607607+$deferred = new React\Promise\Deferred();
608608+609609+$deferred->promise()
610610+ ->then(function ($x) {
611611+ throw new \Exception($x + 1);
612612+ })
613613+ ->catch(function (\Exception $x) {
614614+ // Propagate the rejection
615615+ throw $x;
616616+ })
617617+ ->catch(function (\Exception $x) {
618618+ // Can also propagate by returning another rejection
619619+ return React\Promise\reject(
620620+ new \Exception($x->getMessage() + 1)
621621+ );
622622+ })
623623+ ->catch(function ($x) {
624624+ echo 'Reject ' . $x->getMessage(); // 3
625625+ });
626626+627627+$deferred->resolve(1); // Prints "Reject 3"
628628+```
629629+630630+#### Mixed resolution and rejection forwarding
631631+632632+Just like try/catch, you can choose to propagate or not. Mixing resolutions and
633633+rejections will still forward handler results in a predictable way.
634634+635635+```php
636636+$deferred = new React\Promise\Deferred();
637637+638638+$deferred->promise()
639639+ ->then(function ($x) {
640640+ return $x + 1;
641641+ })
642642+ ->then(function ($x) {
643643+ throw new \Exception($x + 1);
644644+ })
645645+ ->catch(function (\Exception $x) {
646646+ // Handle the rejection, and don't propagate.
647647+ // This is like catch without a rethrow
648648+ return $x->getMessage() + 1;
649649+ })
650650+ ->then(function ($x) {
651651+ echo 'Mixed ' . $x; // 4
652652+ });
653653+654654+$deferred->resolve(1); // Prints "Mixed 4"
655655+```
656656+657657+Install
658658+-------
659659+660660+The recommended way to install this library is [through Composer](https://getcomposer.org/).
661661+[New to Composer?](https://getcomposer.org/doc/00-intro.md)
662662+663663+This project follows [SemVer](https://semver.org/).
664664+This will install the latest supported version from this branch:
665665+666666+```bash
667667+composer require react/promise:^3.2
668668+```
669669+670670+See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
671671+672672+This project aims to run on any platform and thus does not require any PHP
673673+extensions and supports running on PHP 7.1 through current PHP 8+.
674674+It's *highly recommended to use the latest supported PHP version* for this project.
675675+676676+We're committed to providing long-term support (LTS) options and to provide a
677677+smooth upgrade path. If you're using an older PHP version, you may use the
678678+[`2.x` branch](https://github.com/reactphp/promise/tree/2.x) (PHP 5.4+) or
679679+[`1.x` branch](https://github.com/reactphp/promise/tree/1.x) (PHP 5.3+) which both
680680+provide a compatible API but do not take advantage of newer language features.
681681+You may target multiple versions at the same time to support a wider range of
682682+PHP versions like this:
683683+684684+```bash
685685+composer require "react/promise:^3 || ^2 || ^1"
686686+```
687687+688688+## Tests
689689+690690+To run the test suite, you first need to clone this repo and then install all
691691+dependencies [through Composer](https://getcomposer.org/):
692692+693693+```bash
694694+composer install
695695+```
696696+697697+To run the test suite, go to the project root and run:
698698+699699+```bash
700700+vendor/bin/phpunit
701701+```
702702+703703+On top of this, we use PHPStan on max level to ensure type safety across the project:
704704+705705+```bash
706706+vendor/bin/phpstan
707707+```
708708+709709+Credits
710710+-------
711711+712712+Promise is a port of [when.js](https://github.com/cujojs/when)
713713+by [Brian Cavalier](https://github.com/briancavalier).
714714+715715+Also, large parts of the documentation have been ported from the when.js
716716+[Wiki](https://github.com/cujojs/when/wiki) and the
717717+[API docs](https://github.com/cujojs/when/blob/master/docs/api.md).
718718+719719+License
720720+-------
721721+722722+Released under the [MIT](LICENSE) license.
···11+<?php
22+33+namespace React\Promise\Exception;
44+55+/**
66+ * Represents an exception that is a composite of one or more other exceptions.
77+ *
88+ * This exception is useful in situations where a promise must be rejected
99+ * with multiple exceptions. It is used for example to reject the returned
1010+ * promise from `some()` and `any()` when too many input promises reject.
1111+ */
1212+class CompositeException extends \Exception
1313+{
1414+ /** @var \Throwable[] */
1515+ private $throwables;
1616+1717+ /** @param \Throwable[] $throwables */
1818+ public function __construct(array $throwables, string $message = '', int $code = 0, ?\Throwable $previous = null)
1919+ {
2020+ parent::__construct($message, $code, $previous);
2121+2222+ $this->throwables = $throwables;
2323+ }
2424+2525+ /**
2626+ * @return \Throwable[]
2727+ */
2828+ public function getThrowables(): array
2929+ {
3030+ return $this->throwables;
3131+ }
3232+}
···11+<?php
22+33+namespace React\Promise;
44+55+use React\Promise\Internal\RejectedPromise;
66+77+/**
88+ * @template T
99+ * @template-implements PromiseInterface<T>
1010+ */
1111+final class Promise implements PromiseInterface
1212+{
1313+ /** @var (callable(callable(T):void,callable(\Throwable):void):void)|null */
1414+ private $canceller;
1515+1616+ /** @var ?PromiseInterface<T> */
1717+ private $result;
1818+1919+ /** @var list<callable(PromiseInterface<T>):void> */
2020+ private $handlers = [];
2121+2222+ /** @var int */
2323+ private $requiredCancelRequests = 0;
2424+2525+ /** @var bool */
2626+ private $cancelled = false;
2727+2828+ /**
2929+ * @param callable(callable(T):void,callable(\Throwable):void):void $resolver
3030+ * @param (callable(callable(T):void,callable(\Throwable):void):void)|null $canceller
3131+ */
3232+ public function __construct(callable $resolver, ?callable $canceller = null)
3333+ {
3434+ $this->canceller = $canceller;
3535+3636+ // Explicitly overwrite arguments with null values before invoking
3737+ // resolver function. This ensure that these arguments do not show up
3838+ // in the stack trace in PHP 7+ only.
3939+ $cb = $resolver;
4040+ $resolver = $canceller = null;
4141+ $this->call($cb);
4242+ }
4343+4444+ public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
4545+ {
4646+ if (null !== $this->result) {
4747+ return $this->result->then($onFulfilled, $onRejected);
4848+ }
4949+5050+ if (null === $this->canceller) {
5151+ return new static($this->resolver($onFulfilled, $onRejected));
5252+ }
5353+5454+ // This promise has a canceller, so we create a new child promise which
5555+ // has a canceller that invokes the parent canceller if all other
5656+ // followers are also cancelled. We keep a reference to this promise
5757+ // instance for the static canceller function and clear this to avoid
5858+ // keeping a cyclic reference between parent and follower.
5959+ $parent = $this;
6060+ ++$parent->requiredCancelRequests;
6161+6262+ return new static(
6363+ $this->resolver($onFulfilled, $onRejected),
6464+ static function () use (&$parent): void {
6565+ assert($parent instanceof self);
6666+ --$parent->requiredCancelRequests;
6767+6868+ if ($parent->requiredCancelRequests <= 0) {
6969+ $parent->cancel();
7070+ }
7171+7272+ $parent = null;
7373+ }
7474+ );
7575+ }
7676+7777+ /**
7878+ * @template TThrowable of \Throwable
7979+ * @template TRejected
8080+ * @param callable(TThrowable): (PromiseInterface<TRejected>|TRejected) $onRejected
8181+ * @return PromiseInterface<T|TRejected>
8282+ */
8383+ public function catch(callable $onRejected): PromiseInterface
8484+ {
8585+ return $this->then(null, static function (\Throwable $reason) use ($onRejected) {
8686+ if (!_checkTypehint($onRejected, $reason)) {
8787+ return new RejectedPromise($reason);
8888+ }
8989+9090+ /**
9191+ * @var callable(\Throwable):(PromiseInterface<TRejected>|TRejected) $onRejected
9292+ */
9393+ return $onRejected($reason);
9494+ });
9595+ }
9696+9797+ public function finally(callable $onFulfilledOrRejected): PromiseInterface
9898+ {
9999+ return $this->then(static function ($value) use ($onFulfilledOrRejected): PromiseInterface {
100100+ /** @var T $value */
101101+ return resolve($onFulfilledOrRejected())->then(function () use ($value) {
102102+ return $value;
103103+ });
104104+ }, static function (\Throwable $reason) use ($onFulfilledOrRejected): PromiseInterface {
105105+ return resolve($onFulfilledOrRejected())->then(function () use ($reason): RejectedPromise {
106106+ return new RejectedPromise($reason);
107107+ });
108108+ });
109109+ }
110110+111111+ public function cancel(): void
112112+ {
113113+ $this->cancelled = true;
114114+ $canceller = $this->canceller;
115115+ $this->canceller = null;
116116+117117+ $parentCanceller = null;
118118+119119+ if (null !== $this->result) {
120120+ // Forward cancellation to rejected promise to avoid reporting unhandled rejection
121121+ if ($this->result instanceof RejectedPromise) {
122122+ $this->result->cancel();
123123+ }
124124+125125+ // Go up the promise chain and reach the top most promise which is
126126+ // itself not following another promise
127127+ $root = $this->unwrap($this->result);
128128+129129+ // Return if the root promise is already resolved or a
130130+ // FulfilledPromise or RejectedPromise
131131+ if (!$root instanceof self || null !== $root->result) {
132132+ return;
133133+ }
134134+135135+ $root->requiredCancelRequests--;
136136+137137+ if ($root->requiredCancelRequests <= 0) {
138138+ $parentCanceller = [$root, 'cancel'];
139139+ }
140140+ }
141141+142142+ if (null !== $canceller) {
143143+ $this->call($canceller);
144144+ }
145145+146146+ // For BC, we call the parent canceller after our own canceller
147147+ if ($parentCanceller) {
148148+ $parentCanceller();
149149+ }
150150+ }
151151+152152+ /**
153153+ * @deprecated 3.0.0 Use `catch()` instead
154154+ * @see self::catch()
155155+ */
156156+ public function otherwise(callable $onRejected): PromiseInterface
157157+ {
158158+ return $this->catch($onRejected);
159159+ }
160160+161161+ /**
162162+ * @deprecated 3.0.0 Use `finally()` instead
163163+ * @see self::finally()
164164+ */
165165+ public function always(callable $onFulfilledOrRejected): PromiseInterface
166166+ {
167167+ return $this->finally($onFulfilledOrRejected);
168168+ }
169169+170170+ private function resolver(?callable $onFulfilled = null, ?callable $onRejected = null): callable
171171+ {
172172+ return function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected): void {
173173+ $this->handlers[] = static function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject): void {
174174+ $promise = $promise->then($onFulfilled, $onRejected);
175175+176176+ if ($promise instanceof self && $promise->result === null) {
177177+ $promise->handlers[] = static function (PromiseInterface $promise) use ($resolve, $reject): void {
178178+ $promise->then($resolve, $reject);
179179+ };
180180+ } else {
181181+ $promise->then($resolve, $reject);
182182+ }
183183+ };
184184+ };
185185+ }
186186+187187+ private function reject(\Throwable $reason): void
188188+ {
189189+ if (null !== $this->result) {
190190+ return;
191191+ }
192192+193193+ $this->settle(reject($reason));
194194+ }
195195+196196+ /**
197197+ * @param PromiseInterface<T> $result
198198+ */
199199+ private function settle(PromiseInterface $result): void
200200+ {
201201+ $result = $this->unwrap($result);
202202+203203+ if ($result === $this) {
204204+ $result = new RejectedPromise(
205205+ new \LogicException('Cannot resolve a promise with itself.')
206206+ );
207207+ }
208208+209209+ if ($result instanceof self) {
210210+ $result->requiredCancelRequests++;
211211+ } else {
212212+ // Unset canceller only when not following a pending promise
213213+ $this->canceller = null;
214214+ }
215215+216216+ $handlers = $this->handlers;
217217+218218+ $this->handlers = [];
219219+ $this->result = $result;
220220+221221+ foreach ($handlers as $handler) {
222222+ $handler($result);
223223+ }
224224+225225+ // Forward cancellation to rejected promise to avoid reporting unhandled rejection
226226+ if ($this->cancelled && $result instanceof RejectedPromise) {
227227+ $result->cancel();
228228+ }
229229+ }
230230+231231+ /**
232232+ * @param PromiseInterface<T> $promise
233233+ * @return PromiseInterface<T>
234234+ */
235235+ private function unwrap(PromiseInterface $promise): PromiseInterface
236236+ {
237237+ while ($promise instanceof self && null !== $promise->result) {
238238+ /** @var PromiseInterface<T> $promise */
239239+ $promise = $promise->result;
240240+ }
241241+242242+ return $promise;
243243+ }
244244+245245+ /**
246246+ * @param callable(callable(mixed):void,callable(\Throwable):void):void $cb
247247+ */
248248+ private function call(callable $cb): void
249249+ {
250250+ // Explicitly overwrite argument with null value. This ensure that this
251251+ // argument does not show up in the stack trace in PHP 7+ only.
252252+ $callback = $cb;
253253+ $cb = null;
254254+255255+ // Use reflection to inspect number of arguments expected by this callback.
256256+ // We did some careful benchmarking here: Using reflection to avoid unneeded
257257+ // function arguments is actually faster than blindly passing them.
258258+ // Also, this helps avoiding unnecessary function arguments in the call stack
259259+ // if the callback creates an Exception (creating garbage cycles).
260260+ if (\is_array($callback)) {
261261+ $ref = new \ReflectionMethod($callback[0], $callback[1]);
262262+ } elseif (\is_object($callback) && !$callback instanceof \Closure) {
263263+ $ref = new \ReflectionMethod($callback, '__invoke');
264264+ } else {
265265+ assert($callback instanceof \Closure || \is_string($callback));
266266+ $ref = new \ReflectionFunction($callback);
267267+ }
268268+ $args = $ref->getNumberOfParameters();
269269+270270+ try {
271271+ if ($args === 0) {
272272+ $callback();
273273+ } else {
274274+ // Keep references to this promise instance for the static resolve/reject functions.
275275+ // By using static callbacks that are not bound to this instance
276276+ // and passing the target promise instance by reference, we can
277277+ // still execute its resolving logic and still clear this
278278+ // reference when settling the promise. This helps avoiding
279279+ // garbage cycles if any callback creates an Exception.
280280+ // These assumptions are covered by the test suite, so if you ever feel like
281281+ // refactoring this, go ahead, any alternative suggestions are welcome!
282282+ $target =& $this;
283283+284284+ $callback(
285285+ static function ($value) use (&$target): void {
286286+ if ($target !== null) {
287287+ $target->settle(resolve($value));
288288+ $target = null;
289289+ }
290290+ },
291291+ static function (\Throwable $reason) use (&$target): void {
292292+ if ($target !== null) {
293293+ $target->reject($reason);
294294+ $target = null;
295295+ }
296296+ }
297297+ );
298298+ }
299299+ } catch (\Throwable $e) {
300300+ $target = null;
301301+ $this->reject($e);
302302+ }
303303+ }
304304+}
+152
vendor/react/promise/src/PromiseInterface.php
···11+<?php
22+33+namespace React\Promise;
44+55+/**
66+ * @template-covariant T
77+ */
88+interface PromiseInterface
99+{
1010+ /**
1111+ * Transforms a promise's value by applying a function to the promise's fulfillment
1212+ * or rejection value. Returns a new promise for the transformed result.
1313+ *
1414+ * The `then()` method registers new fulfilled and rejection handlers with a promise
1515+ * (all parameters are optional):
1616+ *
1717+ * * `$onFulfilled` will be invoked once the promise is fulfilled and passed
1818+ * the result as the first argument.
1919+ * * `$onRejected` will be invoked once the promise is rejected and passed the
2020+ * reason as the first argument.
2121+ *
2222+ * It returns a new promise that will fulfill with the return value of either
2323+ * `$onFulfilled` or `$onRejected`, whichever is called, or will reject with
2424+ * the thrown exception if either throws.
2525+ *
2626+ * A promise makes the following guarantees about handlers registered in
2727+ * the same call to `then()`:
2828+ *
2929+ * 1. Only one of `$onFulfilled` or `$onRejected` will be called,
3030+ * never both.
3131+ * 2. `$onFulfilled` and `$onRejected` will never be called more
3232+ * than once.
3333+ *
3434+ * @template TFulfilled
3535+ * @template TRejected
3636+ * @param ?(callable((T is void ? null : T)): (PromiseInterface<TFulfilled>|TFulfilled)) $onFulfilled
3737+ * @param ?(callable(\Throwable): (PromiseInterface<TRejected>|TRejected)) $onRejected
3838+ * @return PromiseInterface<($onRejected is null ? ($onFulfilled is null ? T : TFulfilled) : ($onFulfilled is null ? T|TRejected : TFulfilled|TRejected))>
3939+ */
4040+ public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface;
4141+4242+ /**
4343+ * Registers a rejection handler for promise. It is a shortcut for:
4444+ *
4545+ * ```php
4646+ * $promise->then(null, $onRejected);
4747+ * ```
4848+ *
4949+ * Additionally, you can type hint the `$reason` argument of `$onRejected` to catch
5050+ * only specific errors.
5151+ *
5252+ * @template TThrowable of \Throwable
5353+ * @template TRejected
5454+ * @param callable(TThrowable): (PromiseInterface<TRejected>|TRejected) $onRejected
5555+ * @return PromiseInterface<T|TRejected>
5656+ */
5757+ public function catch(callable $onRejected): PromiseInterface;
5858+5959+ /**
6060+ * Allows you to execute "cleanup" type tasks in a promise chain.
6161+ *
6262+ * It arranges for `$onFulfilledOrRejected` to be called, with no arguments,
6363+ * when the promise is either fulfilled or rejected.
6464+ *
6565+ * * If `$promise` fulfills, and `$onFulfilledOrRejected` returns successfully,
6666+ * `$newPromise` will fulfill with the same value as `$promise`.
6767+ * * If `$promise` fulfills, and `$onFulfilledOrRejected` throws or returns a
6868+ * rejected promise, `$newPromise` will reject with the thrown exception or
6969+ * rejected promise's reason.
7070+ * * If `$promise` rejects, and `$onFulfilledOrRejected` returns successfully,
7171+ * `$newPromise` will reject with the same reason as `$promise`.
7272+ * * If `$promise` rejects, and `$onFulfilledOrRejected` throws or returns a
7373+ * rejected promise, `$newPromise` will reject with the thrown exception or
7474+ * rejected promise's reason.
7575+ *
7676+ * `finally()` behaves similarly to the synchronous finally statement. When combined
7777+ * with `catch()`, `finally()` allows you to write code that is similar to the familiar
7878+ * synchronous catch/finally pair.
7979+ *
8080+ * Consider the following synchronous code:
8181+ *
8282+ * ```php
8383+ * try {
8484+ * return doSomething();
8585+ * } catch(\Exception $e) {
8686+ * return handleError($e);
8787+ * } finally {
8888+ * cleanup();
8989+ * }
9090+ * ```
9191+ *
9292+ * Similar asynchronous code (with `doSomething()` that returns a promise) can be
9393+ * written:
9494+ *
9595+ * ```php
9696+ * return doSomething()
9797+ * ->catch('handleError')
9898+ * ->finally('cleanup');
9999+ * ```
100100+ *
101101+ * @param callable(): (void|PromiseInterface<void>) $onFulfilledOrRejected
102102+ * @return PromiseInterface<T>
103103+ */
104104+ public function finally(callable $onFulfilledOrRejected): PromiseInterface;
105105+106106+ /**
107107+ * The `cancel()` method notifies the creator of the promise that there is no
108108+ * further interest in the results of the operation.
109109+ *
110110+ * Once a promise is settled (either fulfilled or rejected), calling `cancel()` on
111111+ * a promise has no effect.
112112+ *
113113+ * @return void
114114+ */
115115+ public function cancel(): void;
116116+117117+ /**
118118+ * [Deprecated] Registers a rejection handler for a promise.
119119+ *
120120+ * This method continues to exist only for BC reasons and to ease upgrading
121121+ * between versions. It is an alias for:
122122+ *
123123+ * ```php
124124+ * $promise->catch($onRejected);
125125+ * ```
126126+ *
127127+ * @template TThrowable of \Throwable
128128+ * @template TRejected
129129+ * @param callable(TThrowable): (PromiseInterface<TRejected>|TRejected) $onRejected
130130+ * @return PromiseInterface<T|TRejected>
131131+ * @deprecated 3.0.0 Use catch() instead
132132+ * @see self::catch()
133133+ */
134134+ public function otherwise(callable $onRejected): PromiseInterface;
135135+136136+ /**
137137+ * [Deprecated] Allows you to execute "cleanup" type tasks in a promise chain.
138138+ *
139139+ * This method continues to exist only for BC reasons and to ease upgrading
140140+ * between versions. It is an alias for:
141141+ *
142142+ * ```php
143143+ * $promise->finally($onFulfilledOrRejected);
144144+ * ```
145145+ *
146146+ * @param callable(): (void|PromiseInterface<void>) $onFulfilledOrRejected
147147+ * @return PromiseInterface<T>
148148+ * @deprecated 3.0.0 Use finally() instead
149149+ * @see self::finally()
150150+ */
151151+ public function always(callable $onFulfilledOrRejected): PromiseInterface;
152152+}
+345
vendor/react/promise/src/functions.php
···11+<?php
22+33+namespace React\Promise;
44+55+use React\Promise\Exception\CompositeException;
66+use React\Promise\Internal\FulfilledPromise;
77+use React\Promise\Internal\RejectedPromise;
88+99+/**
1010+ * Creates a promise for the supplied `$promiseOrValue`.
1111+ *
1212+ * If `$promiseOrValue` is a value, it will be the resolution value of the
1313+ * returned promise.
1414+ *
1515+ * If `$promiseOrValue` is a thenable (any object that provides a `then()` method),
1616+ * a trusted promise that follows the state of the thenable is returned.
1717+ *
1818+ * If `$promiseOrValue` is a promise, it will be returned as is.
1919+ *
2020+ * @template T
2121+ * @param PromiseInterface<T>|T $promiseOrValue
2222+ * @return PromiseInterface<T>
2323+ */
2424+function resolve($promiseOrValue): PromiseInterface
2525+{
2626+ if ($promiseOrValue instanceof PromiseInterface) {
2727+ return $promiseOrValue;
2828+ }
2929+3030+ if (\is_object($promiseOrValue) && \method_exists($promiseOrValue, 'then')) {
3131+ $canceller = null;
3232+3333+ if (\method_exists($promiseOrValue, 'cancel')) {
3434+ $canceller = [$promiseOrValue, 'cancel'];
3535+ assert(\is_callable($canceller));
3636+ }
3737+3838+ /** @var Promise<T> */
3939+ return new Promise(function (callable $resolve, callable $reject) use ($promiseOrValue): void {
4040+ $promiseOrValue->then($resolve, $reject);
4141+ }, $canceller);
4242+ }
4343+4444+ return new FulfilledPromise($promiseOrValue);
4545+}
4646+4747+/**
4848+ * Creates a rejected promise for the supplied `$reason`.
4949+ *
5050+ * If `$reason` is a value, it will be the rejection value of the
5151+ * returned promise.
5252+ *
5353+ * If `$reason` is a promise, its completion value will be the rejected
5454+ * value of the returned promise.
5555+ *
5656+ * This can be useful in situations where you need to reject a promise without
5757+ * throwing an exception. For example, it allows you to propagate a rejection with
5858+ * the value of another promise.
5959+ *
6060+ * @return PromiseInterface<never>
6161+ */
6262+function reject(\Throwable $reason): PromiseInterface
6363+{
6464+ return new RejectedPromise($reason);
6565+}
6666+6767+/**
6868+ * Returns a promise that will resolve only once all the items in
6969+ * `$promisesOrValues` have resolved. The resolution value of the returned promise
7070+ * will be an array containing the resolution values of each of the items in
7171+ * `$promisesOrValues`.
7272+ *
7373+ * @template T
7474+ * @param iterable<PromiseInterface<T>|T> $promisesOrValues
7575+ * @return PromiseInterface<array<T>>
7676+ */
7777+function all(iterable $promisesOrValues): PromiseInterface
7878+{
7979+ $cancellationQueue = new Internal\CancellationQueue();
8080+8181+ /** @var Promise<array<T>> */
8282+ return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
8383+ $toResolve = 0;
8484+ /** @var bool */
8585+ $continue = true;
8686+ $values = [];
8787+8888+ foreach ($promisesOrValues as $i => $promiseOrValue) {
8989+ $cancellationQueue->enqueue($promiseOrValue);
9090+ $values[$i] = null;
9191+ ++$toResolve;
9292+9393+ resolve($promiseOrValue)->then(
9494+ function ($value) use ($i, &$values, &$toResolve, &$continue, $resolve): void {
9595+ $values[$i] = $value;
9696+9797+ if (0 === --$toResolve && !$continue) {
9898+ $resolve($values);
9999+ }
100100+ },
101101+ function (\Throwable $reason) use (&$continue, $reject): void {
102102+ $continue = false;
103103+ $reject($reason);
104104+ }
105105+ );
106106+107107+ if (!$continue && !\is_array($promisesOrValues)) {
108108+ break;
109109+ }
110110+ }
111111+112112+ $continue = false;
113113+ if ($toResolve === 0) {
114114+ $resolve($values);
115115+ }
116116+ }, $cancellationQueue);
117117+}
118118+119119+/**
120120+ * Initiates a competitive race that allows one winner. Returns a promise which is
121121+ * resolved in the same way the first settled promise resolves.
122122+ *
123123+ * The returned promise will become **infinitely pending** if `$promisesOrValues`
124124+ * contains 0 items.
125125+ *
126126+ * @template T
127127+ * @param iterable<PromiseInterface<T>|T> $promisesOrValues
128128+ * @return PromiseInterface<T>
129129+ */
130130+function race(iterable $promisesOrValues): PromiseInterface
131131+{
132132+ $cancellationQueue = new Internal\CancellationQueue();
133133+134134+ /** @var Promise<T> */
135135+ return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
136136+ $continue = true;
137137+138138+ foreach ($promisesOrValues as $promiseOrValue) {
139139+ $cancellationQueue->enqueue($promiseOrValue);
140140+141141+ resolve($promiseOrValue)->then($resolve, $reject)->finally(function () use (&$continue): void {
142142+ $continue = false;
143143+ });
144144+145145+ if (!$continue && !\is_array($promisesOrValues)) {
146146+ break;
147147+ }
148148+ }
149149+ }, $cancellationQueue);
150150+}
151151+152152+/**
153153+ * Returns a promise that will resolve when any one of the items in
154154+ * `$promisesOrValues` resolves. The resolution value of the returned promise
155155+ * will be the resolution value of the triggering item.
156156+ *
157157+ * The returned promise will only reject if *all* items in `$promisesOrValues` are
158158+ * rejected. The rejection value will be an array of all rejection reasons.
159159+ *
160160+ * The returned promise will also reject with a `React\Promise\Exception\LengthException`
161161+ * if `$promisesOrValues` contains 0 items.
162162+ *
163163+ * @template T
164164+ * @param iterable<PromiseInterface<T>|T> $promisesOrValues
165165+ * @return PromiseInterface<T>
166166+ */
167167+function any(iterable $promisesOrValues): PromiseInterface
168168+{
169169+ $cancellationQueue = new Internal\CancellationQueue();
170170+171171+ /** @var Promise<T> */
172172+ return new Promise(function (callable $resolve, callable $reject) use ($promisesOrValues, $cancellationQueue): void {
173173+ $toReject = 0;
174174+ $continue = true;
175175+ $reasons = [];
176176+177177+ foreach ($promisesOrValues as $i => $promiseOrValue) {
178178+ $cancellationQueue->enqueue($promiseOrValue);
179179+ ++$toReject;
180180+181181+ resolve($promiseOrValue)->then(
182182+ function ($value) use ($resolve, &$continue): void {
183183+ $continue = false;
184184+ $resolve($value);
185185+ },
186186+ function (\Throwable $reason) use ($i, &$reasons, &$toReject, $reject, &$continue): void {
187187+ $reasons[$i] = $reason;
188188+189189+ if (0 === --$toReject && !$continue) {
190190+ $reject(new CompositeException(
191191+ $reasons,
192192+ 'All promises rejected.'
193193+ ));
194194+ }
195195+ }
196196+ );
197197+198198+ if (!$continue && !\is_array($promisesOrValues)) {
199199+ break;
200200+ }
201201+ }
202202+203203+ $continue = false;
204204+ if ($toReject === 0 && !$reasons) {
205205+ $reject(new Exception\LengthException(
206206+ 'Must contain at least 1 item but contains only 0 items.'
207207+ ));
208208+ } elseif ($toReject === 0) {
209209+ $reject(new CompositeException(
210210+ $reasons,
211211+ 'All promises rejected.'
212212+ ));
213213+ }
214214+ }, $cancellationQueue);
215215+}
216216+217217+/**
218218+ * Sets the global rejection handler for unhandled promise rejections.
219219+ *
220220+ * Note that rejected promises should always be handled similar to how any
221221+ * exceptions should always be caught in a `try` + `catch` block. If you remove
222222+ * the last reference to a rejected promise that has not been handled, it will
223223+ * report an unhandled promise rejection. See also the [`reject()` function](#reject)
224224+ * for more details.
225225+ *
226226+ * The `?callable $callback` argument MUST be a valid callback function that
227227+ * accepts a single `Throwable` argument or a `null` value to restore the
228228+ * default promise rejection handler. The return value of the callback function
229229+ * will be ignored and has no effect, so you SHOULD return a `void` value. The
230230+ * callback function MUST NOT throw or the program will be terminated with a
231231+ * fatal error.
232232+ *
233233+ * The function returns the previous rejection handler or `null` if using the
234234+ * default promise rejection handler.
235235+ *
236236+ * The default promise rejection handler will log an error message plus its
237237+ * stack trace:
238238+ *
239239+ * ```php
240240+ * // Unhandled promise rejection with RuntimeException: Unhandled in example.php:2
241241+ * React\Promise\reject(new RuntimeException('Unhandled'));
242242+ * ```
243243+ *
244244+ * The promise rejection handler may be used to use customize the log message or
245245+ * write to custom log targets. As a rule of thumb, this function should only be
246246+ * used as a last resort and promise rejections are best handled with either the
247247+ * [`then()` method](#promiseinterfacethen), the
248248+ * [`catch()` method](#promiseinterfacecatch), or the
249249+ * [`finally()` method](#promiseinterfacefinally).
250250+ * See also the [`reject()` function](#reject) for more details.
251251+ *
252252+ * @param callable(\Throwable):void|null $callback
253253+ * @return callable(\Throwable):void|null
254254+ */
255255+function set_rejection_handler(?callable $callback): ?callable
256256+{
257257+ static $current = null;
258258+ $previous = $current;
259259+ $current = $callback;
260260+261261+ return $previous;
262262+}
263263+264264+/**
265265+ * @internal
266266+ */
267267+function _checkTypehint(callable $callback, \Throwable $reason): bool
268268+{
269269+ if (\is_array($callback)) {
270270+ $callbackReflection = new \ReflectionMethod($callback[0], $callback[1]);
271271+ } elseif (\is_object($callback) && !$callback instanceof \Closure) {
272272+ $callbackReflection = new \ReflectionMethod($callback, '__invoke');
273273+ } else {
274274+ assert($callback instanceof \Closure || \is_string($callback));
275275+ $callbackReflection = new \ReflectionFunction($callback);
276276+ }
277277+278278+ $parameters = $callbackReflection->getParameters();
279279+280280+ if (!isset($parameters[0])) {
281281+ return true;
282282+ }
283283+284284+ $expectedException = $parameters[0];
285285+286286+ // Extract the type of the argument and handle different possibilities
287287+ $type = $expectedException->getType();
288288+289289+ $isTypeUnion = true;
290290+ $types = [];
291291+292292+ switch (true) {
293293+ case $type === null:
294294+ break;
295295+ case $type instanceof \ReflectionNamedType:
296296+ $types = [$type];
297297+ break;
298298+ case $type instanceof \ReflectionIntersectionType:
299299+ $isTypeUnion = false;
300300+ case $type instanceof \ReflectionUnionType:
301301+ $types = $type->getTypes();
302302+ break;
303303+ default:
304304+ throw new \LogicException('Unexpected return value of ReflectionParameter::getType');
305305+ }
306306+307307+ // If there is no type restriction, it matches
308308+ if (empty($types)) {
309309+ return true;
310310+ }
311311+312312+ foreach ($types as $type) {
313313+314314+ if ($type instanceof \ReflectionIntersectionType) {
315315+ foreach ($type->getTypes() as $typeToMatch) {
316316+ assert($typeToMatch instanceof \ReflectionNamedType);
317317+ $name = $typeToMatch->getName();
318318+ if (!($matches = (!$typeToMatch->isBuiltin() && $reason instanceof $name))) {
319319+ break;
320320+ }
321321+ }
322322+ assert(isset($matches));
323323+ } else {
324324+ assert($type instanceof \ReflectionNamedType);
325325+ $name = $type->getName();
326326+ $matches = !$type->isBuiltin() && $reason instanceof $name;
327327+ }
328328+329329+ // If we look for a single match (union), we can return early on match
330330+ // If we look for a full match (intersection), we can return early on mismatch
331331+ if ($matches) {
332332+ if ($isTypeUnion) {
333333+ return true;
334334+ }
335335+ } else {
336336+ if (!$isTypeUnion) {
337337+ return false;
338338+ }
339339+ }
340340+ }
341341+342342+ // If we look for a single match (union) and did not return early, we matched no type and are false
343343+ // If we look for a full match (intersection) and did not return early, we matched all types and are true
344344+ return $isTypeUnion ? false : true;
345345+}