mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-29 20:53:30 +00:00
[Web] Update composer libraries
This commit is contained in:
1297 files changed
+71585
-24460
No files matched your search
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -7,7 +9,7 @@ namespace GuzzleHttp\Promise;
|
||||
*/
|
||||
class AggregateException extends RejectionException
|
||||
{
|
||||
public function __construct($msg, array $reasons)
|
||||
public function __construct(string $msg, array $reasons)
|
||||
{
|
||||
parent::__construct(
|
||||
$reasons,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
|
||||
+67
-41
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
use Exception;
|
||||
use Generator;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Creates a promise that is resolved using a generator that yields values or
|
||||
@@ -27,7 +27,7 @@ use Throwable;
|
||||
* $value = (yield createPromise('a'));
|
||||
* try {
|
||||
* $value = (yield createPromise($value . 'b'));
|
||||
* } catch (\Exception $e) {
|
||||
* } catch (\Throwable $e) {
|
||||
* // The promise was rejected.
|
||||
* }
|
||||
* yield $value . 'c';
|
||||
@@ -36,42 +36,46 @@ use Throwable;
|
||||
* // Outputs "abc"
|
||||
* $promise->then(function ($v) { echo $v; });
|
||||
*
|
||||
* @param callable $generatorFn Generator function to wrap into a promise.
|
||||
* @template TValue = mixed
|
||||
* @template TReason = mixed
|
||||
*
|
||||
* @return Promise
|
||||
* @implements PromiseInterface<TValue, TReason>
|
||||
*
|
||||
* @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
|
||||
* @see https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
|
||||
*/
|
||||
final class Coroutine implements PromiseInterface
|
||||
{
|
||||
/**
|
||||
* @var PromiseInterface|null
|
||||
*/
|
||||
private $currentPromise;
|
||||
use NonSerializableTrait;
|
||||
|
||||
/**
|
||||
* @var Generator
|
||||
* @var PromiseInterface<mixed, mixed>|null
|
||||
*/
|
||||
private $generator;
|
||||
private ?PromiseInterface $currentPromise = null;
|
||||
|
||||
/**
|
||||
* @var Promise
|
||||
* @var Generator<mixed, mixed, mixed, mixed>
|
||||
*/
|
||||
private $result;
|
||||
private Generator $generator;
|
||||
|
||||
/**
|
||||
* @var Promise<TValue, TReason>
|
||||
*/
|
||||
private PromiseInterface $result;
|
||||
|
||||
/**
|
||||
* @param callable(): Generator<mixed, mixed, mixed, mixed> $generatorFn
|
||||
*/
|
||||
public function __construct(callable $generatorFn)
|
||||
{
|
||||
$this->generator = $generatorFn();
|
||||
$this->result = new Promise(function () {
|
||||
$this->result = new Promise(function (): void {
|
||||
while (isset($this->currentPromise)) {
|
||||
$this->currentPromise->wait();
|
||||
}
|
||||
});
|
||||
try {
|
||||
$this->nextCoroutine($this->generator->current());
|
||||
} catch (\Exception $exception) {
|
||||
$this->result->reject($exception);
|
||||
} catch (Throwable $throwable) {
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->result->reject($throwable);
|
||||
}
|
||||
}
|
||||
@@ -79,52 +83,76 @@ final class Coroutine implements PromiseInterface
|
||||
/**
|
||||
* Create a new coroutine.
|
||||
*
|
||||
* @return self
|
||||
* @param callable(): Generator<mixed, mixed, mixed, mixed> $generatorFn
|
||||
*
|
||||
* @return self<mixed, mixed>
|
||||
*/
|
||||
public static function of(callable $generatorFn)
|
||||
public static function of(callable $generatorFn): self
|
||||
{
|
||||
return new self($generatorFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TFulfilledValue = never
|
||||
* @template TFulfilledReason = never
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param (callable(TValue): (TFulfilledValue|PromiseInterface<TFulfilledValue, TFulfilledReason>))|null $onFulfilled Invoked when the promise fulfills.
|
||||
* @param (callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>))|null $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<($onFulfilled is null ? TValue : TFulfilledValue)|($onRejected is null ? never : TRejectedValue), ($onFulfilled is null ? never : TFulfilledReason|\Throwable)|($onRejected is null ? TReason : TRejectedReason|\Throwable)>
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface {
|
||||
return $this->result->then($onFulfilled, $onRejected);
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
/**
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>) $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<TValue|TRejectedValue, TRejectedReason|\Throwable>
|
||||
*/
|
||||
public function otherwise(callable $onRejected): PromiseInterface
|
||||
{
|
||||
return $this->result->otherwise($onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true)
|
||||
public function wait(bool $unwrap = true)
|
||||
{
|
||||
return $this->result->wait($unwrap);
|
||||
}
|
||||
|
||||
public function getState()
|
||||
public function getState(): string
|
||||
{
|
||||
return $this->result->getState();
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
public function resolve($value = null): void
|
||||
{
|
||||
$this->result->resolve($value);
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
public function reject($reason): void
|
||||
{
|
||||
$this->result->reject($reason);
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
public function cancel(): void
|
||||
{
|
||||
$this->currentPromise->cancel();
|
||||
if (isset($this->currentPromise)) {
|
||||
$this->currentPromise->cancel();
|
||||
}
|
||||
|
||||
$this->result->cancel();
|
||||
}
|
||||
|
||||
private function nextCoroutine($yielded)
|
||||
private function nextCoroutine($yielded): void
|
||||
{
|
||||
$this->currentPromise = Create::promiseFor($yielded)
|
||||
->then([$this, '_handleSuccess'], [$this, '_handleFailure']);
|
||||
@@ -133,9 +161,10 @@ final class Coroutine implements PromiseInterface
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function _handleSuccess($value)
|
||||
public function _handleSuccess($value): void
|
||||
{
|
||||
unset($this->currentPromise);
|
||||
$this->currentPromise = null;
|
||||
|
||||
try {
|
||||
$next = $this->generator->send($value);
|
||||
if ($this->generator->valid()) {
|
||||
@@ -143,9 +172,7 @@ final class Coroutine implements PromiseInterface
|
||||
} else {
|
||||
$this->result->resolve($value);
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->result->reject($exception);
|
||||
} catch (Throwable $throwable) {
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->result->reject($throwable);
|
||||
}
|
||||
}
|
||||
@@ -153,16 +180,15 @@ final class Coroutine implements PromiseInterface
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function _handleFailure($reason)
|
||||
public function _handleFailure($reason): void
|
||||
{
|
||||
unset($this->currentPromise);
|
||||
$this->currentPromise = null;
|
||||
|
||||
try {
|
||||
$nextYield = $this->generator->throw(Create::exceptionFor($reason));
|
||||
// The throw was caught, so keep iterating on the coroutine
|
||||
$this->nextCoroutine($nextYield);
|
||||
} catch (Exception $exception) {
|
||||
$this->result->reject($exception);
|
||||
} catch (Throwable $throwable) {
|
||||
} catch (\Throwable $throwable) {
|
||||
$this->result->reject($throwable);
|
||||
}
|
||||
}
|
||||
|
||||
+44
-19
@@ -1,17 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
final class Create
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise for a value if the value is not a promise.
|
||||
* Returns `$value` when it is already a Guzzle promise, wraps foreign
|
||||
* thenables in a Guzzle promise, or returns a fulfilled promise for plain
|
||||
* values.
|
||||
*
|
||||
* @param mixed $value Promise or value.
|
||||
* @template TValue
|
||||
* @template TPromise of PromiseInterface<mixed, mixed> = PromiseInterface<mixed, mixed>
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param TValue|TPromise $value Promise or value.
|
||||
*
|
||||
* @return ($value is PromiseInterface ? TPromise : FulfilledPromise<TValue, never>)
|
||||
*/
|
||||
public static function promiseFor($value)
|
||||
public static function promiseFor($value): PromiseInterface
|
||||
{
|
||||
if ($value instanceof PromiseInterface) {
|
||||
return $value;
|
||||
@@ -23,6 +34,7 @@ final class Create
|
||||
$cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
|
||||
$promise = new Promise($wfn, $cfn);
|
||||
$value->then([$promise, 'resolve'], [$promise, 'reject']);
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
@@ -30,14 +42,18 @@ final class Create
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rejected promise for a reason if the reason is not a promise.
|
||||
* If the provided reason is a promise, then it is returned as-is.
|
||||
* Returns `$reason` when it is already a promise, or returns a rejected
|
||||
* promise for plain reasons.
|
||||
*
|
||||
* @param mixed $reason Promise or reason.
|
||||
* @template TReason
|
||||
* @template TValue = never
|
||||
* @template TPromise of PromiseInterface<mixed, mixed> = PromiseInterface<mixed, mixed>
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param TReason|TPromise $reason Promise or reason.
|
||||
*
|
||||
* @return ($reason is PromiseInterface ? TPromise : RejectedPromise<TValue, TReason>)
|
||||
*/
|
||||
public static function rejectionFor($reason)
|
||||
public static function rejectionFor($reason): PromiseInterface
|
||||
{
|
||||
if ($reason instanceof PromiseInterface) {
|
||||
return $reason;
|
||||
@@ -47,15 +63,16 @@ final class Create
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exception for a rejected promise value.
|
||||
* Returns throwable reasons as-is, or wraps non-throwable reasons in
|
||||
* `RejectionException`.
|
||||
*
|
||||
* @param mixed $reason
|
||||
* @template TReason
|
||||
*
|
||||
* @return \Exception|\Throwable
|
||||
* @param TReason $reason
|
||||
*/
|
||||
public static function exceptionFor($reason)
|
||||
public static function exceptionFor($reason): \Throwable
|
||||
{
|
||||
if ($reason instanceof \Exception || $reason instanceof \Throwable) {
|
||||
if ($reason instanceof \Throwable) {
|
||||
return $reason;
|
||||
}
|
||||
|
||||
@@ -63,13 +80,17 @@ final class Create
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the given value.
|
||||
* Returns an iterator for arrays, iterators, iterator aggregates, and
|
||||
* traversables.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
*
|
||||
* @return \Iterator
|
||||
* @param iterable<TKey, TValue> $value
|
||||
*
|
||||
* @return \Iterator<TKey, TValue>
|
||||
*/
|
||||
public static function iterFor($value)
|
||||
public static function iterFor(iterable $value): \Iterator
|
||||
{
|
||||
if ($value instanceof \Iterator) {
|
||||
return $value;
|
||||
@@ -79,6 +100,10 @@ final class Create
|
||||
return new \ArrayIterator($value);
|
||||
}
|
||||
|
||||
return new \ArrayIterator([$value]);
|
||||
if ($value instanceof \IteratorAggregate) {
|
||||
return self::iterFor($value->getIterator());
|
||||
}
|
||||
|
||||
return new \IteratorIterator($value);
|
||||
}
|
||||
}
|
||||
+71
-43
@@ -1,37 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
final class Each
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an iterator that yields promises or values, returns a promise that
|
||||
* is fulfilled with a null value when the iterator has been consumed or
|
||||
* the aggregate promise has been fulfilled or rejected.
|
||||
*
|
||||
* $onFulfilled is a function that accepts the fulfilled value, iterator
|
||||
* index, and the aggregate promise. The callback can invoke any necessary
|
||||
* $onFulfilled is a function that accepts the fulfilled value, iterable
|
||||
* key, and the aggregate promise. The callback can invoke any necessary
|
||||
* side effects and choose to resolve or reject the aggregate if needed.
|
||||
*
|
||||
* $onRejected is a function that accepts the rejection reason, iterator
|
||||
* index, and the aggregate promise. The callback can invoke any necessary
|
||||
* $onRejected is a function that accepts the rejection reason, iterable
|
||||
* key, and the aggregate promise. The callback can invoke any necessary
|
||||
* side effects and choose to resolve or reject the aggregate if needed.
|
||||
*
|
||||
* @param mixed $iterable Iterator or array to iterate over.
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
* The config array accepts a concurrency option matching {@see ofLimit}.
|
||||
* Other config keys are ignored by this wrapper.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $iterable Iterator or array to iterate over.
|
||||
* @param (callable(TValue, TKey, PromiseInterface<mixed, mixed>): mixed)|null $onFulfilled
|
||||
* @param (callable(TReason, TKey, PromiseInterface<mixed, mixed>): mixed)|null $onRejected
|
||||
* @param array{concurrency?: int|(callable(int): int)} $config Configuration options.
|
||||
*
|
||||
* @return PromiseInterface<mixed, mixed>
|
||||
*/
|
||||
public static function of(
|
||||
$iterable,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return (new EachPromise($iterable, [
|
||||
'fulfilled' => $onFulfilled,
|
||||
'rejected' => $onRejected
|
||||
]))->promise();
|
||||
iterable $iterable,
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null,
|
||||
array $config = []
|
||||
): PromiseInterface {
|
||||
$eachConfig = [];
|
||||
|
||||
if (null !== $onFulfilled) {
|
||||
$eachConfig['fulfilled'] = $onFulfilled;
|
||||
}
|
||||
|
||||
if (null !== $onRejected) {
|
||||
$eachConfig['rejected'] = $onRejected;
|
||||
}
|
||||
|
||||
if (isset($config['concurrency'])) {
|
||||
$eachConfig['concurrency'] = $config['concurrency'];
|
||||
}
|
||||
|
||||
return (new EachPromise($iterable, $eachConfig))->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,49 +66,51 @@ final class Each
|
||||
*
|
||||
* $concurrency may be an integer or a function that accepts the number of
|
||||
* pending promises and returns a numeric concurrency limit value to allow
|
||||
* for dynamic a concurrency size.
|
||||
* for a dynamic concurrency size.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $iterable
|
||||
* @param int|(callable(int): int) $concurrency
|
||||
* @param (callable(TValue, TKey, PromiseInterface<mixed, mixed>): mixed)|null $onFulfilled
|
||||
* @param (callable(TReason, TKey, PromiseInterface<mixed, mixed>): mixed)|null $onRejected
|
||||
*
|
||||
* @return PromiseInterface<mixed, mixed>
|
||||
*/
|
||||
public static function ofLimit(
|
||||
$iterable,
|
||||
iterable $iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return (new EachPromise($iterable, [
|
||||
'fulfilled' => $onFulfilled,
|
||||
'rejected' => $onRejected,
|
||||
'concurrency' => $concurrency
|
||||
]))->promise();
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface {
|
||||
return self::of($iterable, $onFulfilled, $onRejected, ['concurrency' => $concurrency]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like limit, but ensures that no promise in the given $iterable argument
|
||||
* is rejected. If any promise is rejected, then the aggregate promise is
|
||||
* rejected with the encountered rejection.
|
||||
* Like ofLimit, but rejects the aggregate promise on the first rejection.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $iterable
|
||||
* @param int|(callable(int): int) $concurrency
|
||||
* @param (callable(TValue, TKey, PromiseInterface<mixed, mixed>): mixed)|null $onFulfilled
|
||||
*
|
||||
* @return PromiseInterface<mixed, mixed>
|
||||
*/
|
||||
public static function ofLimitAll(
|
||||
$iterable,
|
||||
iterable $iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null
|
||||
) {
|
||||
return each_limit(
|
||||
?callable $onFulfilled = null
|
||||
): PromiseInterface {
|
||||
return self::ofLimit(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
$onFulfilled,
|
||||
function ($reason, $idx, PromiseInterface $aggregate) {
|
||||
function ($reason, $idx, PromiseInterface $aggregate): void {
|
||||
$aggregate->reject($reason);
|
||||
}
|
||||
);
|
||||
|
||||
+104
-56
@@ -1,34 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Represents a promise that iterates over many promises and invokes
|
||||
* side-effect functions in the process.
|
||||
*
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @implements PromisorInterface<mixed, mixed>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class EachPromise implements PromisorInterface
|
||||
{
|
||||
private $pending = [];
|
||||
use NonSerializableTrait;
|
||||
|
||||
private $nextPendingIndex = 0;
|
||||
/** @var array<int, PromiseInterface<mixed, mixed>>|null */
|
||||
private ?array $pending = [];
|
||||
|
||||
/** @var \Iterator|null */
|
||||
private $iterable;
|
||||
private int $nextPendingIndex = 0;
|
||||
|
||||
/** @var callable|int|null */
|
||||
/** @var \Iterator<TKey, TValue|PromiseInterface<TValue, TReason>>|null */
|
||||
private ?\Iterator $iterable;
|
||||
|
||||
/** @var (callable(int): int)|int|null */
|
||||
private $concurrency;
|
||||
|
||||
/** @var callable|null */
|
||||
/** @var (callable(TValue, TKey, PromiseInterface<mixed, mixed>): mixed)|null */
|
||||
private $onFulfilled;
|
||||
|
||||
/** @var callable|null */
|
||||
/** @var (callable(TReason, TKey, PromiseInterface<mixed, mixed>): mixed)|null */
|
||||
private $onRejected;
|
||||
|
||||
/** @var Promise|null */
|
||||
private $aggregate;
|
||||
/** @var Promise<mixed, mixed>|null */
|
||||
private ?Promise $aggregate = null;
|
||||
|
||||
/** @var bool|null */
|
||||
private $mutex;
|
||||
private ?bool $mutex = null;
|
||||
|
||||
private bool $stepWhileLocked = false;
|
||||
|
||||
/**
|
||||
* Configuration hash can include the following key value pairs:
|
||||
@@ -48,10 +62,14 @@ class EachPromise implements PromisorInterface
|
||||
* allowed number of outstanding concurrently executing promises,
|
||||
* creating a capped pool of promises. There is no limit by default.
|
||||
*
|
||||
* @param mixed $iterable Promises or values to iterate.
|
||||
* @param array $config Configuration options
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $iterable Promises or values to iterate.
|
||||
* @param array{
|
||||
* fulfilled?: callable(TValue, TKey, PromiseInterface<mixed, mixed>): mixed,
|
||||
* rejected?: callable(TReason, TKey, PromiseInterface<mixed, mixed>): mixed,
|
||||
* concurrency?: int|(callable(int): int)
|
||||
* } $config Configuration options
|
||||
*/
|
||||
public function __construct($iterable, array $config = [])
|
||||
public function __construct(iterable $iterable, array $config = [])
|
||||
{
|
||||
$this->iterable = Create::iterFor($iterable);
|
||||
|
||||
@@ -68,8 +86,10 @@ class EachPromise implements PromisorInterface
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-suppress InvalidNullableReturnType */
|
||||
public function promise()
|
||||
/**
|
||||
* @return PromiseInterface<mixed, mixed>
|
||||
*/
|
||||
public function promise(): PromiseInterface
|
||||
{
|
||||
if ($this->aggregate) {
|
||||
return $this->aggregate;
|
||||
@@ -77,43 +97,56 @@ class EachPromise implements PromisorInterface
|
||||
|
||||
try {
|
||||
$this->createPromise();
|
||||
/** @psalm-assert Promise $this->aggregate */
|
||||
$this->iterable->rewind();
|
||||
$this->refillPending();
|
||||
if (!$this->pending) {
|
||||
Utils::queue()->add(function (): void {
|
||||
if (!$this->aggregate || State::isSettled($this->aggregate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->checkIfFinished();
|
||||
} catch (\Throwable $e) {
|
||||
$this->aggregate->reject($e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->aggregate->reject($e);
|
||||
} catch (\Exception $e) {
|
||||
$this->aggregate->reject($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-suppress NullableReturnStatement
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
return $this->aggregate;
|
||||
}
|
||||
|
||||
private function createPromise()
|
||||
private function createPromise(): void
|
||||
{
|
||||
$this->mutex = false;
|
||||
$this->aggregate = new Promise(function () {
|
||||
if ($this->checkIfFinished()) {
|
||||
return;
|
||||
}
|
||||
reset($this->pending);
|
||||
// Consume a potentially fluctuating list of promises while
|
||||
// ensuring that indexes are maintained (precluding array_shift).
|
||||
while ($promise = current($this->pending)) {
|
||||
next($this->pending);
|
||||
$promise->wait();
|
||||
if (Is::settled($this->aggregate)) {
|
||||
$this->aggregate = new Promise(function (): void {
|
||||
while (true) {
|
||||
if ($this->checkIfFinished()) {
|
||||
return;
|
||||
}
|
||||
reset($this->pending);
|
||||
// Consume a potentially fluctuating list of promises while
|
||||
// ensuring that indexes are maintained (precluding array_shift).
|
||||
while ($promise = current($this->pending)) {
|
||||
next($this->pending);
|
||||
$promise->wait();
|
||||
if (State::isSettled($this->aggregate)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Refill and re-sweep; give up only when nothing remains.
|
||||
$this->refillPending();
|
||||
if (State::isSettled($this->aggregate) || !$this->pending) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Clear the references when the promise is resolved.
|
||||
$clearFn = function () {
|
||||
$clearFn = function (): void {
|
||||
$this->iterable = $this->concurrency = $this->pending = null;
|
||||
$this->onFulfilled = $this->onRejected = null;
|
||||
$this->nextPendingIndex = 0;
|
||||
@@ -122,18 +155,24 @@ class EachPromise implements PromisorInterface
|
||||
$this->aggregate->then($clearFn, $clearFn);
|
||||
}
|
||||
|
||||
private function refillPending()
|
||||
private function refillPending(): void
|
||||
{
|
||||
if (!$this->concurrency) {
|
||||
// Add all pending promises.
|
||||
while ($this->addPending() && $this->advanceIterator());
|
||||
while ($this->addPending() && $this->advanceIterator()) {
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Add only up to N pending promises.
|
||||
$concurrency = is_callable($this->concurrency)
|
||||
? call_user_func($this->concurrency, count($this->pending))
|
||||
? ($this->concurrency)(count($this->pending))
|
||||
: $this->concurrency;
|
||||
// The callable can settle the aggregate; admit nothing more.
|
||||
if (State::isSettled($this->aggregate)) {
|
||||
return;
|
||||
}
|
||||
$concurrency = max($concurrency - count($this->pending), 0);
|
||||
// Concurrency may be set to 0 to disallow new promises.
|
||||
if (!$concurrency) {
|
||||
@@ -147,10 +186,11 @@ class EachPromise implements PromisorInterface
|
||||
// next value to yield until promise callbacks are called.
|
||||
while (--$concurrency
|
||||
&& $this->advanceIterator()
|
||||
&& $this->addPending());
|
||||
&& $this->addPending()) {
|
||||
}
|
||||
}
|
||||
|
||||
private function addPending()
|
||||
private function addPending(): bool
|
||||
{
|
||||
if (!$this->iterable || !$this->iterable->valid()) {
|
||||
return false;
|
||||
@@ -164,10 +204,9 @@ class EachPromise implements PromisorInterface
|
||||
$idx = $this->nextPendingIndex++;
|
||||
|
||||
$this->pending[$idx] = $promise->then(
|
||||
function ($value) use ($idx, $key) {
|
||||
function ($value) use ($idx, $key): void {
|
||||
if ($this->onFulfilled) {
|
||||
call_user_func(
|
||||
$this->onFulfilled,
|
||||
($this->onFulfilled)(
|
||||
$value,
|
||||
$key,
|
||||
$this->aggregate
|
||||
@@ -175,10 +214,9 @@ class EachPromise implements PromisorInterface
|
||||
}
|
||||
$this->step($idx);
|
||||
},
|
||||
function ($reason) use ($idx, $key) {
|
||||
function ($reason) use ($idx, $key): void {
|
||||
if ($this->onRejected) {
|
||||
call_user_func(
|
||||
$this->onRejected,
|
||||
($this->onRejected)(
|
||||
$reason,
|
||||
$key,
|
||||
$this->aggregate
|
||||
@@ -191,11 +229,13 @@ class EachPromise implements PromisorInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
private function advanceIterator()
|
||||
private function advanceIterator(): bool
|
||||
{
|
||||
// Place a lock on the iterator so that we ensure to not recurse,
|
||||
// preventing fatal generator errors.
|
||||
if ($this->mutex) {
|
||||
$this->stepWhileLocked = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -204,22 +244,28 @@ class EachPromise implements PromisorInterface
|
||||
try {
|
||||
$this->iterable->next();
|
||||
$this->mutex = false;
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->aggregate->reject($e);
|
||||
$this->mutex = false;
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
$this->aggregate->reject($e);
|
||||
$this->mutex = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run the completion check that locked steps skipped.
|
||||
if ($this->stepWhileLocked) {
|
||||
$this->stepWhileLocked = false;
|
||||
if (!State::isSettled($this->aggregate)) {
|
||||
$this->checkIfFinished();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function step($idx)
|
||||
private function step(int $idx): void
|
||||
{
|
||||
// If the promise was already resolved, then ignore this step.
|
||||
if (Is::settled($this->aggregate)) {
|
||||
if (State::isSettled($this->aggregate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,11 +280,13 @@ class EachPromise implements PromisorInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function checkIfFinished()
|
||||
/** @phpstan-impure */
|
||||
private function checkIfFinished(): bool
|
||||
{
|
||||
if (!$this->pending && !$this->iterable->valid()) {
|
||||
// Resolve the promise if there's nothing left to do.
|
||||
$this->aggregate->resolve(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -7,11 +9,22 @@ namespace GuzzleHttp\Promise;
|
||||
*
|
||||
* Thenning off of this promise will invoke the onFulfilled callback
|
||||
* immediately and ignore other callbacks.
|
||||
*
|
||||
* @template TValue = mixed
|
||||
* @template TReason = never
|
||||
*
|
||||
* @implements PromiseInterface<TValue, TReason>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class FulfilledPromise implements PromiseInterface
|
||||
{
|
||||
/** @var TValue */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param TValue $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
if (is_object($value) && method_exists($value, 'then')) {
|
||||
@@ -23,10 +36,21 @@ class FulfilledPromise implements PromiseInterface
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TFulfilledValue = never
|
||||
* @template TFulfilledReason = never
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param (callable(TValue): (TFulfilledValue|PromiseInterface<TFulfilledValue, TFulfilledReason>))|null $onFulfilled Invoked when the promise fulfills.
|
||||
* @param (callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>))|null $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return ($onFulfilled is null ? self<TValue, TReason> : PromiseInterface<TFulfilledValue, TFulfilledReason|\Throwable>)
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface {
|
||||
// Return itself if there is no onFulfilled function.
|
||||
if (!$onFulfilled) {
|
||||
return $this;
|
||||
@@ -35,14 +59,12 @@ class FulfilledPromise implements PromiseInterface
|
||||
$queue = Utils::queue();
|
||||
$p = new Promise([$queue, 'run']);
|
||||
$value = $this->value;
|
||||
$queue->add(static function () use ($p, $value, $onFulfilled) {
|
||||
if (Is::pending($p)) {
|
||||
$queue->add(static function () use ($p, $value, $onFulfilled): void {
|
||||
if (State::isPending($p)) {
|
||||
try {
|
||||
$p->resolve($onFulfilled($value));
|
||||
} catch (\Throwable $e) {
|
||||
$p->reject($e);
|
||||
} catch (\Exception $e) {
|
||||
$p->reject($e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -50,34 +72,39 @@ class FulfilledPromise implements PromiseInterface
|
||||
return $p;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
/**
|
||||
* @param callable(TReason): mixed $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return self<TValue, TReason>
|
||||
*/
|
||||
public function otherwise(callable $onRejected): PromiseInterface
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true, $defaultDelivery = null)
|
||||
public function wait(bool $unwrap = true)
|
||||
{
|
||||
return $unwrap ? $this->value : null;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
public function getState(): string
|
||||
{
|
||||
return self::FULFILLED;
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
public function resolve($value = null): void
|
||||
{
|
||||
if ($value !== $this->value) {
|
||||
throw new \LogicException("Cannot resolve a fulfilled promise");
|
||||
throw new \LogicException('Cannot resolve a fulfilled promise');
|
||||
}
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
public function reject($reason): void
|
||||
{
|
||||
throw new \LogicException("Cannot reject a fulfilled promise");
|
||||
throw new \LogicException('Cannot reject a fulfilled promise');
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
public function cancel(): void
|
||||
{
|
||||
// pass
|
||||
}
|
||||
|
||||
+57
-12
@@ -1,46 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* @deprecated Is will be removed in guzzlehttp/promises:4.0. Use State instead.
|
||||
*/
|
||||
final class Is
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is pending.
|
||||
*
|
||||
* @return bool
|
||||
* @deprecated Is::pending() will be removed in guzzlehttp/promises:4.0. Use
|
||||
* State::isPending() instead.
|
||||
*/
|
||||
public static function pending(PromiseInterface $promise)
|
||||
public static function pending(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::PENDING;
|
||||
\trigger_deprecation(
|
||||
'guzzlehttp/promises',
|
||||
'3.1',
|
||||
'%s() is deprecated and will be removed in 4.0. Use %s::isPending() instead.',
|
||||
__METHOD__,
|
||||
State::class
|
||||
);
|
||||
|
||||
return State::isPending($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled or rejected.
|
||||
*
|
||||
* @return bool
|
||||
* @deprecated Is::settled() will be removed in guzzlehttp/promises:4.0. Use
|
||||
* State::isSettled() instead.
|
||||
*/
|
||||
public static function settled(PromiseInterface $promise)
|
||||
public static function settled(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() !== PromiseInterface::PENDING;
|
||||
\trigger_deprecation(
|
||||
'guzzlehttp/promises',
|
||||
'3.1',
|
||||
'%s() is deprecated and will be removed in 4.0. Use %s::isSettled() instead.',
|
||||
__METHOD__,
|
||||
State::class
|
||||
);
|
||||
|
||||
return State::isSettled($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled.
|
||||
*
|
||||
* @return bool
|
||||
* @deprecated Is::fulfilled() will be removed in guzzlehttp/promises:4.0.
|
||||
* Use State::isFulfilled() instead.
|
||||
*/
|
||||
public static function fulfilled(PromiseInterface $promise)
|
||||
public static function fulfilled(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::FULFILLED;
|
||||
\trigger_deprecation(
|
||||
'guzzlehttp/promises',
|
||||
'3.1',
|
||||
'%s() is deprecated and will be removed in 4.0. Use %s::isFulfilled() instead.',
|
||||
__METHOD__,
|
||||
State::class
|
||||
);
|
||||
|
||||
return State::isFulfilled($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is rejected.
|
||||
*
|
||||
* @return bool
|
||||
* @deprecated Is::rejected() will be removed in guzzlehttp/promises:4.0.
|
||||
* Use State::isRejected() instead.
|
||||
*/
|
||||
public static function rejected(PromiseInterface $promise)
|
||||
public static function rejected(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::REJECTED;
|
||||
\trigger_deprecation(
|
||||
'guzzlehttp/promises',
|
||||
'3.1',
|
||||
'%s() is deprecated and will be removed in 4.0. Use %s::isRejected() instead.',
|
||||
__METHOD__,
|
||||
State::class
|
||||
);
|
||||
|
||||
return State::isRejected($promise);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait NonSerializableTrait
|
||||
{
|
||||
public function __serialize(): array
|
||||
{
|
||||
throw new \LogicException(static::class.' should never be serialized');
|
||||
}
|
||||
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
throw new \LogicException(static::class.' should never be unserialized');
|
||||
}
|
||||
}
|
||||
+83
-38
@@ -1,63 +1,110 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Promises/A+ implementation that avoids recursion when possible.
|
||||
*
|
||||
* @link https://promisesaplus.com/
|
||||
* @template TValue = mixed
|
||||
* @template TReason = mixed
|
||||
*
|
||||
* @implements PromiseInterface<TValue, TReason>
|
||||
*
|
||||
* @see https://promisesaplus.com/
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class Promise implements PromiseInterface
|
||||
{
|
||||
private $state = self::PENDING;
|
||||
use NonSerializableTrait;
|
||||
|
||||
/** @var self::PENDING|self::FULFILLED|self::REJECTED */
|
||||
private string $state = self::PENDING;
|
||||
|
||||
/** @var TValue|TReason|PromiseInterface<TValue, TReason>|null */
|
||||
private $result;
|
||||
|
||||
/** @var (callable(): void)|null */
|
||||
private $cancelFn;
|
||||
|
||||
/** @var (callable(bool): void)|null */
|
||||
private $waitFn;
|
||||
private $waitList;
|
||||
private $handlers = [];
|
||||
|
||||
/** @var list<Promise<mixed, mixed>>|null */
|
||||
private ?array $waitList = null;
|
||||
|
||||
/** @var list<array{0: PromiseInterface<mixed, mixed>, 1: callable|null, 2: callable|null}>|null */
|
||||
private ?array $handlers = [];
|
||||
|
||||
/**
|
||||
* @param callable $waitFn Fn that when invoked resolves the promise.
|
||||
* @param callable $cancelFn Fn that when invoked cancels the promise.
|
||||
* @param (callable(bool): void)|null $waitFn Fn that when invoked resolves the promise.
|
||||
* @param (callable(): void)|null $cancelFn Fn that when invoked cancels the promise.
|
||||
*/
|
||||
public function __construct(
|
||||
callable $waitFn = null,
|
||||
callable $cancelFn = null
|
||||
?callable $waitFn = null,
|
||||
?callable $cancelFn = null
|
||||
) {
|
||||
$this->waitFn = $waitFn;
|
||||
$this->cancelFn = $cancelFn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TFulfilledValue = never
|
||||
* @template TFulfilledReason = never
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param (callable(TValue): (TFulfilledValue|PromiseInterface<TFulfilledValue, TFulfilledReason>))|null $onFulfilled Invoked when the promise fulfills.
|
||||
* @param (callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>))|null $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<($onFulfilled is null ? TValue : TFulfilledValue)|($onRejected is null ? never : TRejectedValue), ($onFulfilled is null ? never : TFulfilledReason|\Throwable)|($onRejected is null ? TReason : TRejectedReason|\Throwable)>
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface {
|
||||
if ($this->state === self::PENDING) {
|
||||
$p = new Promise(null, [$this, 'cancel']);
|
||||
$this->handlers[] = [$p, $onFulfilled, $onRejected];
|
||||
$p->waitList = $this->waitList;
|
||||
$p->waitList[] = $this;
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
// Return a fulfilled promise and immediately invoke any callbacks.
|
||||
if ($this->state === self::FULFILLED) {
|
||||
$promise = Create::promiseFor($this->result);
|
||||
return $onFulfilled ? $promise->then($onFulfilled) : $promise;
|
||||
|
||||
return $promise->then($onFulfilled, $onRejected);
|
||||
}
|
||||
|
||||
// It's either cancelled or rejected, so return a rejected promise
|
||||
// and immediately invoke any callbacks.
|
||||
$rejection = Create::rejectionFor($this->result);
|
||||
return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
|
||||
|
||||
/** @var PromiseInterface<($onFulfilled is null ? TValue : TFulfilledValue)|($onRejected is null ? never : TRejectedValue), ($onFulfilled is null ? never : TFulfilledReason|\Throwable)|($onRejected is null ? TReason : TRejectedReason|\Throwable)> $promise */
|
||||
$promise = $onRejected ? $rejection->then(null, $onRejected) : $rejection;
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
/**
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>) $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<TValue|TRejectedValue, TRejectedReason|\Throwable>
|
||||
*/
|
||||
public function otherwise(callable $onRejected): PromiseInterface
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true)
|
||||
public function wait(bool $unwrap = true)
|
||||
{
|
||||
$this->waitIfPending();
|
||||
|
||||
@@ -71,14 +118,16 @@ class Promise implements PromiseInterface
|
||||
// It's rejected so "unwrap" and throw an exception.
|
||||
throw Create::exceptionFor($this->result);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
public function getState(): string
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
public function cancel(): void
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
return;
|
||||
@@ -93,8 +142,6 @@ class Promise implements PromiseInterface
|
||||
$fn();
|
||||
} catch (\Throwable $e) {
|
||||
$this->reject($e);
|
||||
} catch (\Exception $e) {
|
||||
$this->reject($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,17 +152,17 @@ class Promise implements PromiseInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
public function resolve($value = null): void
|
||||
{
|
||||
$this->settle(self::FULFILLED, $value);
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
public function reject($reason): void
|
||||
{
|
||||
$this->settle(self::REJECTED, $reason);
|
||||
}
|
||||
|
||||
private function settle($state, $value)
|
||||
private function settle(string $state, $value): void
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
// Ignore calls with the same resolution.
|
||||
@@ -148,23 +195,23 @@ class Promise implements PromiseInterface
|
||||
if (!is_object($value) || !method_exists($value, 'then')) {
|
||||
$id = $state === self::FULFILLED ? 1 : 2;
|
||||
// It's a success, so resolve the handlers in the queue.
|
||||
Utils::queue()->add(static function () use ($id, $value, $handlers) {
|
||||
Utils::queue()->add(static function () use ($id, $value, $handlers): void {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler($id, $value, $handler);
|
||||
}
|
||||
});
|
||||
} elseif ($value instanceof Promise && Is::pending($value)) {
|
||||
} elseif ($value instanceof Promise && State::isPending($value)) {
|
||||
// We can just merge our handlers onto the next promise.
|
||||
$value->handlers = array_merge($value->handlers, $handlers);
|
||||
} else {
|
||||
// Resolve the handlers when the forwarded promise is resolved.
|
||||
$value->then(
|
||||
static function ($value) use ($handlers) {
|
||||
static function ($value) use ($handlers): void {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler(1, $value, $handler);
|
||||
}
|
||||
},
|
||||
static function ($reason) use ($handlers) {
|
||||
static function ($reason) use ($handlers): void {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler(2, $reason, $handler);
|
||||
}
|
||||
@@ -180,14 +227,14 @@ class Promise implements PromiseInterface
|
||||
* @param mixed $value Value to pass to the callback.
|
||||
* @param array $handler Array of handler data (promise and callbacks).
|
||||
*/
|
||||
private static function callHandler($index, $value, array $handler)
|
||||
private static function callHandler(int $index, $value, array $handler): void
|
||||
{
|
||||
/** @var PromiseInterface $promise */
|
||||
/** @var PromiseInterface<mixed, mixed> $promise */
|
||||
$promise = $handler[0];
|
||||
|
||||
// The promise may have been cancelled or resolved before placing
|
||||
// this thunk in the queue.
|
||||
if (Is::settled($promise)) {
|
||||
if (State::isSettled($promise)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -211,12 +258,10 @@ class Promise implements PromiseInterface
|
||||
}
|
||||
} catch (\Throwable $reason) {
|
||||
$promise->reject($reason);
|
||||
} catch (\Exception $reason) {
|
||||
$promise->reject($reason);
|
||||
}
|
||||
}
|
||||
|
||||
private function waitIfPending()
|
||||
private function waitIfPending(): void
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
return;
|
||||
@@ -227,9 +272,9 @@ class Promise implements PromiseInterface
|
||||
} else {
|
||||
// If there's no wait function, then reject the promise.
|
||||
$this->reject('Cannot wait on a promise that has '
|
||||
. 'no internal wait function. You must provide a wait '
|
||||
. 'function when constructing the promise to be able to '
|
||||
. 'wait on a promise.');
|
||||
.'no internal wait function. You must provide a wait '
|
||||
.'function when constructing the promise to be able to '
|
||||
.'wait on a promise.');
|
||||
}
|
||||
|
||||
Utils::queue()->run();
|
||||
@@ -240,13 +285,13 @@ class Promise implements PromiseInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeWaitFn()
|
||||
private function invokeWaitFn(): void
|
||||
{
|
||||
try {
|
||||
$wfn = $this->waitFn;
|
||||
$this->waitFn = null;
|
||||
$wfn(true);
|
||||
} catch (\Exception $reason) {
|
||||
} catch (\Throwable $reason) {
|
||||
if ($this->state === self::PENDING) {
|
||||
// The promise has not been resolved yet, so reject the promise
|
||||
// with the exception.
|
||||
@@ -259,7 +304,7 @@ class Promise implements PromiseInterface
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeWaitList()
|
||||
private function invokeWaitList(): void
|
||||
{
|
||||
$waitList = $this->waitList;
|
||||
$this->waitList = null;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -9,27 +11,35 @@ namespace GuzzleHttp\Promise;
|
||||
* which registers callbacks to receive either a promise’s eventual value or
|
||||
* the reason why the promise cannot be fulfilled.
|
||||
*
|
||||
* @link https://promisesaplus.com/
|
||||
* @template TValue = mixed
|
||||
* @template TReason = mixed
|
||||
*
|
||||
* @see https://promisesaplus.com/
|
||||
*/
|
||||
interface PromiseInterface
|
||||
{
|
||||
const PENDING = 'pending';
|
||||
const FULFILLED = 'fulfilled';
|
||||
const REJECTED = 'rejected';
|
||||
public const PENDING = 'pending';
|
||||
public const FULFILLED = 'fulfilled';
|
||||
public const REJECTED = 'rejected';
|
||||
|
||||
/**
|
||||
* Appends fulfillment and rejection handlers to the promise, and returns
|
||||
* a new promise resolving to the return value of the called handler.
|
||||
*
|
||||
* @param callable $onFulfilled Invoked when the promise fulfills.
|
||||
* @param callable $onRejected Invoked when the promise is rejected.
|
||||
* @template TFulfilledValue = never
|
||||
* @template TFulfilledReason = never
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param (callable(TValue): (TFulfilledValue|PromiseInterface<TFulfilledValue, TFulfilledReason>))|null $onFulfilled Invoked when the promise fulfills.
|
||||
* @param (callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>))|null $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<($onFulfilled is null ? TValue : TFulfilledValue)|($onRejected is null ? never : TRejectedValue), ($onFulfilled is null ? never : TFulfilledReason|\Throwable)|($onRejected is null ? TReason : TRejectedReason|\Throwable)>
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
);
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface;
|
||||
|
||||
/**
|
||||
* Appends a rejection handler callback to the promise, and returns a new
|
||||
@@ -37,11 +47,14 @@ interface PromiseInterface
|
||||
* or to its original fulfillment value if the promise is instead
|
||||
* fulfilled.
|
||||
*
|
||||
* @param callable $onRejected Invoked when the promise is rejected.
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>) $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<TValue|TRejectedValue, TRejectedReason|\Throwable>
|
||||
*/
|
||||
public function otherwise(callable $onRejected);
|
||||
public function otherwise(callable $onRejected): PromiseInterface;
|
||||
|
||||
/**
|
||||
* Get the state of the promise ("pending", "rejected", or "fulfilled").
|
||||
@@ -49,34 +62,45 @@ interface PromiseInterface
|
||||
* The three states can be checked against the constants defined on
|
||||
* PromiseInterface: PENDING, FULFILLED, and REJECTED.
|
||||
*
|
||||
* @return string
|
||||
* The state describes how this promise was settled, not the eventual
|
||||
* outcome: a promise that was resolved with another promise, directly or
|
||||
* by returning one from a then() handler, reports FULFILLED while the
|
||||
* inner promise may still be pending, and wait() can still throw if the
|
||||
* inner promise rejects. Poll the state only on promises settled with
|
||||
* plain values, or call wait() first.
|
||||
*
|
||||
* @return self::PENDING|self::FULFILLED|self::REJECTED
|
||||
*
|
||||
* @see https://github.com/guzzle/promises/issues/101
|
||||
*/
|
||||
public function getState();
|
||||
public function getState(): string;
|
||||
|
||||
/**
|
||||
* Resolve the promise with the given value.
|
||||
* Resolve the promise with the given value, or with null if no value is given.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param TValue|PromiseInterface<TValue, TReason>|null $value
|
||||
*
|
||||
* @throws \RuntimeException if the promise is already resolved.
|
||||
* @throws \LogicException if the promise is already settled with a
|
||||
* conflicting resolution.
|
||||
*/
|
||||
public function resolve($value);
|
||||
public function resolve($value = null): void;
|
||||
|
||||
/**
|
||||
* Reject the promise with the given reason.
|
||||
*
|
||||
* @param mixed $reason
|
||||
* @param TReason $reason
|
||||
*
|
||||
* @throws \RuntimeException if the promise is already resolved.
|
||||
* @throws \LogicException if the promise is already settled with a
|
||||
* conflicting resolution.
|
||||
*/
|
||||
public function reject($reason);
|
||||
public function reject($reason): void;
|
||||
|
||||
/**
|
||||
* Cancels the promise if possible.
|
||||
*
|
||||
* @link https://github.com/promises-aplus/cancellation-spec/issues/7
|
||||
* @see https://github.com/promises-aplus/cancellation-spec/issues/7
|
||||
*/
|
||||
public function cancel();
|
||||
public function cancel(): void;
|
||||
|
||||
/**
|
||||
* Waits until the promise completes if possible.
|
||||
@@ -86,12 +110,10 @@ interface PromiseInterface
|
||||
*
|
||||
* If the promise cannot be waited on, then the promise will be rejected.
|
||||
*
|
||||
* @param bool $unwrap
|
||||
*
|
||||
* @return mixed
|
||||
* @return ($unwrap is true ? TValue : null)
|
||||
*
|
||||
* @throws \LogicException if the promise has no wait function or if the
|
||||
* promise does not settle after waiting.
|
||||
*/
|
||||
public function wait($unwrap = true);
|
||||
public function wait(bool $unwrap = true);
|
||||
}
|
||||
@@ -1,16 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Interface used with classes that return a promise.
|
||||
*
|
||||
* @template TValue = mixed
|
||||
* @template TReason = mixed
|
||||
*/
|
||||
interface PromisorInterface
|
||||
{
|
||||
/**
|
||||
* Returns a promise.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @return PromiseInterface<TValue, TReason>
|
||||
*/
|
||||
public function promise();
|
||||
public function promise(): PromiseInterface;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -7,11 +9,22 @@ namespace GuzzleHttp\Promise;
|
||||
*
|
||||
* Thenning off of this promise will invoke the onRejected callback
|
||||
* immediately and ignore other callbacks.
|
||||
*
|
||||
* @template TValue = never
|
||||
* @template TReason = mixed
|
||||
*
|
||||
* @implements PromiseInterface<TValue, TReason>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RejectedPromise implements PromiseInterface
|
||||
{
|
||||
/** @var TReason */
|
||||
private $reason;
|
||||
|
||||
/**
|
||||
* @param TReason $reason
|
||||
*/
|
||||
public function __construct($reason)
|
||||
{
|
||||
if (is_object($reason) && method_exists($reason, 'then')) {
|
||||
@@ -23,10 +36,21 @@ class RejectedPromise implements PromiseInterface
|
||||
$this->reason = $reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TFulfilledValue = never
|
||||
* @template TFulfilledReason = never
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param (callable(TValue): (TFulfilledValue|PromiseInterface<TFulfilledValue, TFulfilledReason>))|null $onFulfilled Invoked when the promise fulfills.
|
||||
* @param (callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>))|null $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return ($onRejected is null ? self<TValue, TReason> : PromiseInterface<TRejectedValue, TRejectedReason|\Throwable>)
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
?callable $onFulfilled = null,
|
||||
?callable $onRejected = null
|
||||
): PromiseInterface {
|
||||
// If there's no onRejected callback then just return self.
|
||||
if (!$onRejected) {
|
||||
return $this;
|
||||
@@ -35,17 +59,14 @@ class RejectedPromise implements PromiseInterface
|
||||
$queue = Utils::queue();
|
||||
$reason = $this->reason;
|
||||
$p = new Promise([$queue, 'run']);
|
||||
$queue->add(static function () use ($p, $reason, $onRejected) {
|
||||
if (Is::pending($p)) {
|
||||
$queue->add(static function () use ($p, $reason, $onRejected): void {
|
||||
if (State::isPending($p)) {
|
||||
try {
|
||||
// Return a resolved promise if onRejected does not throw.
|
||||
$p->resolve($onRejected($reason));
|
||||
} catch (\Throwable $e) {
|
||||
// onRejected threw, so return a rejected promise.
|
||||
$p->reject($e);
|
||||
} catch (\Exception $e) {
|
||||
// onRejected threw, so return a rejected promise.
|
||||
$p->reject($e);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -53,12 +74,20 @@ class RejectedPromise implements PromiseInterface
|
||||
return $p;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
/**
|
||||
* @template TRejectedValue = never
|
||||
* @template TRejectedReason = never
|
||||
*
|
||||
* @param callable(TReason): (TRejectedValue|PromiseInterface<TRejectedValue, TRejectedReason>) $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface<TRejectedValue, TRejectedReason|\Throwable>
|
||||
*/
|
||||
public function otherwise(callable $onRejected): PromiseInterface
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true, $defaultDelivery = null)
|
||||
public function wait(bool $unwrap = true)
|
||||
{
|
||||
if ($unwrap) {
|
||||
throw Create::exceptionFor($this->reason);
|
||||
@@ -67,24 +96,24 @@ class RejectedPromise implements PromiseInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
public function getState(): string
|
||||
{
|
||||
return self::REJECTED;
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
public function resolve($value = null): void
|
||||
{
|
||||
throw new \LogicException("Cannot resolve a rejected promise");
|
||||
throw new \LogicException('Cannot resolve a rejected promise');
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
public function reject($reason): void
|
||||
{
|
||||
if ($reason !== $this->reason) {
|
||||
throw new \LogicException("Cannot reject a rejected promise");
|
||||
throw new \LogicException('Cannot reject a rejected promise');
|
||||
}
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
public function cancel(): void
|
||||
{
|
||||
// pass
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -13,24 +15,23 @@ class RejectionException extends \RuntimeException
|
||||
private $reason;
|
||||
|
||||
/**
|
||||
* @param mixed $reason Rejection reason.
|
||||
* @param string $description Optional description
|
||||
* @param mixed $reason Rejection reason.
|
||||
* @param string|null $description Optional description.
|
||||
*/
|
||||
public function __construct($reason, $description = null)
|
||||
public function __construct($reason, ?string $description = null)
|
||||
{
|
||||
$this->reason = $reason;
|
||||
|
||||
$message = 'The promise was rejected';
|
||||
|
||||
if ($description) {
|
||||
$message .= ' with reason: ' . $description;
|
||||
$message .= ' with reason: '.$description;
|
||||
} elseif (is_string($reason)
|
||||
|| (is_object($reason) && method_exists($reason, '__toString'))
|
||||
) {
|
||||
$message .= ' with reason: ' . $this->reason;
|
||||
$message .= ' with reason: '.$this->reason;
|
||||
} elseif ($reason instanceof \JsonSerializable) {
|
||||
$message .= ' with reason: '
|
||||
. json_encode($this->reason, JSON_PRETTY_PRINT);
|
||||
$message .= ' with reason: '.json_encode($this->reason, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
parent::__construct($message);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
final class State
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is pending.
|
||||
*/
|
||||
public static function isPending(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled or rejected.
|
||||
*/
|
||||
public static function isSettled(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() !== PromiseInterface::PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled.
|
||||
*/
|
||||
public static function isFulfilled(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::FULFILLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is rejected.
|
||||
*/
|
||||
public static function isRejected(PromiseInterface $promise): bool
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::REJECTED;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
@@ -10,16 +12,21 @@ namespace GuzzleHttp\Promise;
|
||||
* by calling the `run()` function of the global task queue in an event loop.
|
||||
*
|
||||
* GuzzleHttp\Promise\Utils::queue()->run();
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class TaskQueue implements TaskQueueInterface
|
||||
{
|
||||
private $enableShutdown = true;
|
||||
private $queue = [];
|
||||
use NonSerializableTrait;
|
||||
|
||||
public function __construct($withShutdown = true)
|
||||
private bool $enableShutdown = true;
|
||||
/** @var list<callable(): void> */
|
||||
private array $queue = [];
|
||||
|
||||
public function __construct(bool $withShutdown = true)
|
||||
{
|
||||
if ($withShutdown) {
|
||||
register_shutdown_function(function () {
|
||||
register_shutdown_function(function (): void {
|
||||
if ($this->enableShutdown) {
|
||||
// Only run the tasks if an E_ERROR didn't occur.
|
||||
$err = error_get_last();
|
||||
@@ -31,20 +38,23 @@ class TaskQueue implements TaskQueueInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
public function isEmpty(): bool
|
||||
{
|
||||
return !$this->queue;
|
||||
}
|
||||
|
||||
public function add(callable $task)
|
||||
/**
|
||||
* @param callable(): void $task
|
||||
*/
|
||||
public function add(callable $task): void
|
||||
{
|
||||
$this->queue[] = $task;
|
||||
}
|
||||
|
||||
public function run()
|
||||
public function run(): void
|
||||
{
|
||||
while ($task = array_shift($this->queue)) {
|
||||
/** @var callable $task */
|
||||
/** @var callable(): void $task */
|
||||
$task();
|
||||
}
|
||||
}
|
||||
@@ -60,7 +70,7 @@ class TaskQueue implements TaskQueueInterface
|
||||
*
|
||||
* Note: This shutdown will occur before any destructors are triggered.
|
||||
*/
|
||||
public function disableShutdown()
|
||||
public function disableShutdown(): void
|
||||
{
|
||||
$this->enableShutdown = false;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
interface TaskQueueInterface
|
||||
{
|
||||
/**
|
||||
* Returns true if the queue is empty.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty();
|
||||
public function isEmpty(): bool;
|
||||
|
||||
/**
|
||||
* Adds a task to the queue that will be executed the next time run is
|
||||
* called.
|
||||
*
|
||||
* @param callable(): void $task
|
||||
*/
|
||||
public function add(callable $task);
|
||||
public function add(callable $task): void;
|
||||
|
||||
/**
|
||||
* Execute all of the pending task in the queue.
|
||||
*/
|
||||
public function run();
|
||||
public function run(): void;
|
||||
}
|
||||
+186
-72
@@ -1,9 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
final class Utils
|
||||
{
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the global task queue used for promise resolution.
|
||||
*
|
||||
@@ -17,11 +23,9 @@ final class Utils
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param TaskQueueInterface $assign Optionally specify a new queue instance.
|
||||
*
|
||||
* @return TaskQueueInterface
|
||||
* @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
|
||||
*/
|
||||
public static function queue(TaskQueueInterface $assign = null)
|
||||
public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
|
||||
{
|
||||
static $queue;
|
||||
|
||||
@@ -35,26 +39,26 @@ final class Utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a function to run in the task queue when it is next `run()` and
|
||||
* returns a promise that is fulfilled or rejected with the result.
|
||||
* Adds a task to the global queue and returns a promise that is fulfilled
|
||||
* or rejected with the task result.
|
||||
*
|
||||
* @param callable $task Task function to run.
|
||||
* @template TValue
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param callable(): TValue $task Task function to run.
|
||||
*
|
||||
* @return PromiseInterface<TValue, \Throwable>
|
||||
*/
|
||||
public static function task(callable $task)
|
||||
public static function task(callable $task): PromiseInterface
|
||||
{
|
||||
$queue = self::queue();
|
||||
$promise = new Promise([$queue, 'run']);
|
||||
$queue->add(function () use ($task, $promise) {
|
||||
$queue->add(function () use ($task, $promise): void {
|
||||
try {
|
||||
if (Is::pending($promise)) {
|
||||
if (State::isPending($promise)) {
|
||||
$promise->resolve($task());
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$promise->reject($e);
|
||||
} catch (\Exception $e) {
|
||||
$promise->reject($e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,7 +66,7 @@ final class Utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously waits on a promise to resolve and returns an inspection
|
||||
* Synchronously waits on a promise to settle and returns an inspection
|
||||
* state array.
|
||||
*
|
||||
* Returns a state associative array containing a "state" key mapping to a
|
||||
@@ -71,43 +75,78 @@ final class Utils
|
||||
* promise. If the promise is rejected, the array will contain a "reason"
|
||||
* key mapping to the rejection reason of the promise.
|
||||
*
|
||||
* @param PromiseInterface $promise Promise or value.
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return array
|
||||
* @param PromiseInterface<TValue, TReason> $promise Promise to inspect.
|
||||
*
|
||||
* @return array{state: PromiseInterface::FULFILLED, value: TValue}|array{state: PromiseInterface::REJECTED, reason: TReason|\Throwable}|array{state: PromiseInterface::PENDING}
|
||||
*/
|
||||
public static function inspect(PromiseInterface $promise)
|
||||
public static function inspect(PromiseInterface $promise): array
|
||||
{
|
||||
$result = null;
|
||||
$getResult = static function () use (&$result): ?array {
|
||||
return $result;
|
||||
};
|
||||
|
||||
$inspection = $promise->then(
|
||||
static function ($value) use (&$result): void {
|
||||
$result = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
|
||||
},
|
||||
static function ($reason) use (&$result): void {
|
||||
$result = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
return [
|
||||
'state' => PromiseInterface::FULFILLED,
|
||||
'value' => $promise->wait()
|
||||
];
|
||||
} catch (RejectionException $e) {
|
||||
return ['state' => PromiseInterface::REJECTED, 'reason' => $e->getReason()];
|
||||
$inspection->wait(false);
|
||||
} catch (\Throwable $e) {
|
||||
return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
|
||||
} catch (\Exception $e) {
|
||||
$settled = $getResult();
|
||||
if (null !== $settled) {
|
||||
return $settled;
|
||||
}
|
||||
|
||||
if (State::isSettled($promise)) {
|
||||
try {
|
||||
self::queue()->run();
|
||||
} catch (\Throwable $queueError) {
|
||||
return ['state' => PromiseInterface::REJECTED, 'reason' => $queueError];
|
||||
}
|
||||
|
||||
$settled = $getResult();
|
||||
if (null !== $settled) {
|
||||
return $settled;
|
||||
}
|
||||
}
|
||||
|
||||
return ['state' => PromiseInterface::REJECTED, 'reason' => $e];
|
||||
}
|
||||
|
||||
return $getResult() ?? ['state' => $promise->getState()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on all of the provided promises, but does not unwrap rejected
|
||||
* promises as thrown exception.
|
||||
* promises as a thrown exception.
|
||||
*
|
||||
* Returns an array of inspection state arrays.
|
||||
* Returns an array of inspection state arrays keyed like the input
|
||||
* iterable.
|
||||
*
|
||||
* @see inspect for the inspection state array format.
|
||||
*
|
||||
* @param PromiseInterface[] $promises Traversable of promises to wait upon.
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return array
|
||||
* @param iterable<TKey, PromiseInterface<TValue, TReason>> $promises Traversable of promises to wait upon.
|
||||
*
|
||||
* @return array<TKey, array{state: PromiseInterface::FULFILLED, value: TValue}|array{state: PromiseInterface::REJECTED, reason: TReason|\Throwable}|array{state: PromiseInterface::PENDING}>
|
||||
*/
|
||||
public static function inspectAll($promises)
|
||||
public static function inspectAll(iterable $promises): array
|
||||
{
|
||||
$results = [];
|
||||
foreach ($promises as $key => $promise) {
|
||||
$results[$key] = inspect($promise);
|
||||
$results[$key] = self::inspect($promise);
|
||||
}
|
||||
|
||||
return $results;
|
||||
@@ -120,14 +159,17 @@ final class Utils
|
||||
* order the promises were provided). An exception is thrown if any of the
|
||||
* promises are rejected.
|
||||
*
|
||||
* @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return array
|
||||
* @param iterable<TKey, PromiseInterface<TValue, TReason>> $promises Iterable of PromiseInterface objects to wait on.
|
||||
*
|
||||
* @throws \Exception on error
|
||||
* @throws \Throwable on error in PHP >=7
|
||||
* @return array<TKey, TValue>
|
||||
*
|
||||
* @throws \Throwable on error
|
||||
*/
|
||||
public static function unwrap($promises)
|
||||
public static function unwrap(iterable $promises): array
|
||||
{
|
||||
$results = [];
|
||||
foreach ($promises as $key => $promise) {
|
||||
@@ -145,34 +187,45 @@ final class Utils
|
||||
* respective positions to the original array. If any promise in the array
|
||||
* rejects, the returned promise is rejected with the rejection reason.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
* @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
|
||||
* The config array accepts a concurrency option for lazy iterables. Other
|
||||
* config keys are ignored by this wrapper.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $promises Promises or values.
|
||||
* @param bool $recursive If true, resolves newly-added entries until no unprocessed entries or pending promises remain.
|
||||
* @param array{concurrency?: int|(callable(int): int)} $config Configuration options.
|
||||
*
|
||||
* @return PromiseInterface<array<TKey, TValue>, TReason|\Throwable>
|
||||
*/
|
||||
public static function all($promises, $recursive = false)
|
||||
public static function all(iterable $promises, bool $recursive = false, array $config = []): PromiseInterface
|
||||
{
|
||||
$results = [];
|
||||
$promise = Each::of(
|
||||
$promises,
|
||||
function ($value, $idx) use (&$results) {
|
||||
function ($value, $idx) use (&$results): void {
|
||||
$results[$idx] = $value;
|
||||
},
|
||||
function ($reason, $idx, Promise $aggregate) {
|
||||
$aggregate->reject($reason);
|
||||
}
|
||||
function ($reason, $idx, PromiseInterface $aggregate): void {
|
||||
if (State::isPending($aggregate)) {
|
||||
$aggregate->reject($reason);
|
||||
}
|
||||
},
|
||||
$config
|
||||
)->then(function () use (&$results) {
|
||||
ksort($results);
|
||||
|
||||
return $results;
|
||||
});
|
||||
|
||||
if (true === $recursive) {
|
||||
$promise = $promise->then(function ($results) use ($recursive, &$promises) {
|
||||
foreach ($promises as $promise) {
|
||||
if (Is::pending($promise)) {
|
||||
return self::all($promises, $recursive);
|
||||
}
|
||||
$promise = $promise->then(function ($results) use (&$promises, $config) {
|
||||
if (self::shouldRecurse($promises, $results)) {
|
||||
return self::all($promises, true, $config);
|
||||
}
|
||||
|
||||
return $results;
|
||||
});
|
||||
}
|
||||
@@ -186,25 +239,28 @@ final class Utils
|
||||
*
|
||||
* When count amount of promises have been fulfilled, the returned promise
|
||||
* is fulfilled with an array that contains the fulfillment values of the
|
||||
* winners in order of resolution.
|
||||
* winners, in the order they appear in the input.
|
||||
*
|
||||
* This promise is rejected with a {@see AggregateException} if the number
|
||||
* of fulfilled promises is less than the desired $count.
|
||||
*
|
||||
* @param int $count Total number of promises.
|
||||
* @param mixed $promises Promises or values.
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param int $count Total number of promises.
|
||||
* @param iterable<TValue|PromiseInterface<TValue, TReason>> $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface<list<TValue>, \Throwable>
|
||||
*/
|
||||
public static function some($count, $promises)
|
||||
public static function some(int $count, iterable $promises): PromiseInterface
|
||||
{
|
||||
$results = [];
|
||||
$rejections = [];
|
||||
|
||||
return Each::of(
|
||||
$promise = Each::of(
|
||||
$promises,
|
||||
function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
|
||||
if (Is::settled($p)) {
|
||||
function ($value, $idx, PromiseInterface $p) use (&$results, $count): void {
|
||||
if (State::isSettled($p)) {
|
||||
return;
|
||||
}
|
||||
$results[$idx] = $value;
|
||||
@@ -212,7 +268,7 @@ final class Utils
|
||||
$p->resolve(null);
|
||||
}
|
||||
},
|
||||
function ($reason) use (&$rejections) {
|
||||
function ($reason) use (&$rejections): void {
|
||||
$rejections[] = $reason;
|
||||
}
|
||||
)->then(
|
||||
@@ -224,53 +280,111 @@ final class Utils
|
||||
);
|
||||
}
|
||||
ksort($results);
|
||||
|
||||
return array_values($results);
|
||||
}
|
||||
);
|
||||
|
||||
/** @var PromiseInterface<list<TValue>, \Throwable> $promise */
|
||||
return $promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like some(), with 1 as count. However, if the promise fulfills, the
|
||||
* fulfillment value is not an array of 1 but the value directly.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param iterable<TValue|PromiseInterface<TValue, TReason>> $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface<TValue, \Throwable>
|
||||
*/
|
||||
public static function any($promises)
|
||||
public static function any(iterable $promises): PromiseInterface
|
||||
{
|
||||
return self::some(1, $promises)->then(function ($values) {
|
||||
return self::some(1, $promises)->then(function (array $values) {
|
||||
return $values[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that is fulfilled when all of the provided promises have
|
||||
* been fulfilled or rejected.
|
||||
* Returns a promise that is fulfilled when all of the provided promises
|
||||
* have been fulfilled or rejected.
|
||||
*
|
||||
* The returned promise is fulfilled with an array of inspection state arrays.
|
||||
* The returned promise is fulfilled with an array of inspection state
|
||||
* arrays.
|
||||
*
|
||||
* The config array accepts a concurrency option for lazy iterables. Other
|
||||
* config keys are ignored by this wrapper.
|
||||
*
|
||||
* @see inspect for the inspection state array format.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
* @template TKey of array-key
|
||||
* @template TValue
|
||||
* @template TReason
|
||||
*
|
||||
* @return PromiseInterface
|
||||
* @param iterable<TKey, TValue|PromiseInterface<TValue, TReason>> $promises Promises or values.
|
||||
* @param bool $recursive If true, settles newly-added entries until no unprocessed entries or pending promises remain.
|
||||
* @param array{concurrency?: int|(callable(int): int)} $config Configuration options.
|
||||
*
|
||||
* @return PromiseInterface<array<TKey, array{state: PromiseInterface::FULFILLED, value: TValue}|array{state: PromiseInterface::REJECTED, reason: TReason|\Throwable}>, \Throwable>
|
||||
*/
|
||||
public static function settle($promises)
|
||||
public static function settle(iterable $promises, bool $recursive = false, array $config = []): PromiseInterface
|
||||
{
|
||||
$results = [];
|
||||
|
||||
return Each::of(
|
||||
$promise = Each::of(
|
||||
$promises,
|
||||
function ($value, $idx) use (&$results) {
|
||||
function ($value, $idx) use (&$results): void {
|
||||
$results[$idx] = ['state' => PromiseInterface::FULFILLED, 'value' => $value];
|
||||
},
|
||||
function ($reason, $idx) use (&$results) {
|
||||
function ($reason, $idx) use (&$results): void {
|
||||
$results[$idx] = ['state' => PromiseInterface::REJECTED, 'reason' => $reason];
|
||||
}
|
||||
},
|
||||
$config
|
||||
)->then(function () use (&$results) {
|
||||
ksort($results);
|
||||
|
||||
return $results;
|
||||
});
|
||||
|
||||
if (true === $recursive) {
|
||||
$promise = $promise->then(function ($results) use (&$promises, $config) {
|
||||
if (self::shouldRecurse($promises, $results)) {
|
||||
return self::settle($promises, true, $config);
|
||||
}
|
||||
|
||||
return $results;
|
||||
});
|
||||
}
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TKey of array-key
|
||||
*
|
||||
* @param iterable<TKey, mixed> $promises Promises or values.
|
||||
* @param array<TKey, mixed> $results Results already collected for a pass.
|
||||
*/
|
||||
private static function shouldRecurse(iterable $promises, array $results): bool
|
||||
{
|
||||
// A consumed generator cannot be traversed again, so a recursive
|
||||
// pass has nothing further to observe.
|
||||
if ($promises instanceof \Generator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($promises as $key => $promise) {
|
||||
if (!array_key_exists($key, $results)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($promise instanceof PromiseInterface && State::isPending($promise)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Get the global task queue used for promise resolution.
|
||||
*
|
||||
* This task queue MUST be run in an event loop in order for promises to be
|
||||
* settled asynchronously. It will be automatically run when synchronously
|
||||
* waiting on a promise.
|
||||
*
|
||||
* <code>
|
||||
* while ($eventLoop->isRunning()) {
|
||||
* GuzzleHttp\Promise\queue()->run();
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @param TaskQueueInterface $assign Optionally specify a new queue instance.
|
||||
*
|
||||
* @return TaskQueueInterface
|
||||
*
|
||||
* @deprecated queue will be removed in guzzlehttp/promises:2.0. Use Utils::queue instead.
|
||||
*/
|
||||
function queue(TaskQueueInterface $assign = null)
|
||||
{
|
||||
return Utils::queue($assign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a function to run in the task queue when it is next `run()` and returns
|
||||
* a promise that is fulfilled or rejected with the result.
|
||||
*
|
||||
* @param callable $task Task function to run.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated task will be removed in guzzlehttp/promises:2.0. Use Utils::task instead.
|
||||
*/
|
||||
function task(callable $task)
|
||||
{
|
||||
return Utils::task($task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise for a value if the value is not a promise.
|
||||
*
|
||||
* @param mixed $value Promise or value.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated promise_for will be removed in guzzlehttp/promises:2.0. Use Create::promiseFor instead.
|
||||
*/
|
||||
function promise_for($value)
|
||||
{
|
||||
return Create::promiseFor($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rejected promise for a reason if the reason is not a promise. If
|
||||
* the provided reason is a promise, then it is returned as-is.
|
||||
*
|
||||
* @param mixed $reason Promise or reason.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated rejection_for will be removed in guzzlehttp/promises:2.0. Use Create::rejectionFor instead.
|
||||
*/
|
||||
function rejection_for($reason)
|
||||
{
|
||||
return Create::rejectionFor($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exception for a rejected promise value.
|
||||
*
|
||||
* @param mixed $reason
|
||||
*
|
||||
* @return \Exception|\Throwable
|
||||
*
|
||||
* @deprecated exception_for will be removed in guzzlehttp/promises:2.0. Use Create::exceptionFor instead.
|
||||
*/
|
||||
function exception_for($reason)
|
||||
{
|
||||
return Create::exceptionFor($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return \Iterator
|
||||
*
|
||||
* @deprecated iter_for will be removed in guzzlehttp/promises:2.0. Use Create::iterFor instead.
|
||||
*/
|
||||
function iter_for($value)
|
||||
{
|
||||
return Create::iterFor($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously waits on a promise to resolve and returns an inspection state
|
||||
* array.
|
||||
*
|
||||
* Returns a state associative array containing a "state" key mapping to a
|
||||
* valid promise state. If the state of the promise is "fulfilled", the array
|
||||
* will contain a "value" key mapping to the fulfilled value of the promise. If
|
||||
* the promise is rejected, the array will contain a "reason" key mapping to
|
||||
* the rejection reason of the promise.
|
||||
*
|
||||
* @param PromiseInterface $promise Promise or value.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspect instead.
|
||||
*/
|
||||
function inspect(PromiseInterface $promise)
|
||||
{
|
||||
return Utils::inspect($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on all of the provided promises, but does not unwrap rejected promises
|
||||
* as thrown exception.
|
||||
*
|
||||
* Returns an array of inspection state arrays.
|
||||
*
|
||||
* @see inspect for the inspection state array format.
|
||||
*
|
||||
* @param PromiseInterface[] $promises Traversable of promises to wait upon.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @deprecated inspect will be removed in guzzlehttp/promises:2.0. Use Utils::inspectAll instead.
|
||||
*/
|
||||
function inspect_all($promises)
|
||||
{
|
||||
return Utils::inspectAll($promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on all of the provided promises and returns the fulfilled values.
|
||||
*
|
||||
* Returns an array that contains the value of each promise (in the same order
|
||||
* the promises were provided). An exception is thrown if any of the promises
|
||||
* are rejected.
|
||||
*
|
||||
* @param iterable<PromiseInterface> $promises Iterable of PromiseInterface objects to wait on.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception on error
|
||||
* @throws \Throwable on error in PHP >=7
|
||||
*
|
||||
* @deprecated unwrap will be removed in guzzlehttp/promises:2.0. Use Utils::unwrap instead.
|
||||
*/
|
||||
function unwrap($promises)
|
||||
{
|
||||
return Utils::unwrap($promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of promises, return a promise that is fulfilled when all the
|
||||
* items in the array are fulfilled.
|
||||
*
|
||||
* The promise's fulfillment value is an array with fulfillment values at
|
||||
* respective positions to the original array. If any promise in the array
|
||||
* rejects, the returned promise is rejected with the rejection reason.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
* @param bool $recursive If true, resolves new promises that might have been added to the stack during its own resolution.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated all will be removed in guzzlehttp/promises:2.0. Use Utils::all instead.
|
||||
*/
|
||||
function all($promises, $recursive = false)
|
||||
{
|
||||
return Utils::all($promises, $recursive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a competitive race between multiple promises or values (values will
|
||||
* become immediately fulfilled promises).
|
||||
*
|
||||
* When count amount of promises have been fulfilled, the returned promise is
|
||||
* fulfilled with an array that contains the fulfillment values of the winners
|
||||
* in order of resolution.
|
||||
*
|
||||
* This promise is rejected with a {@see AggregateException} if the number of
|
||||
* fulfilled promises is less than the desired $count.
|
||||
*
|
||||
* @param int $count Total number of promises.
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated some will be removed in guzzlehttp/promises:2.0. Use Utils::some instead.
|
||||
*/
|
||||
function some($count, $promises)
|
||||
{
|
||||
return Utils::some($count, $promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like some(), with 1 as count. However, if the promise fulfills, the
|
||||
* fulfillment value is not an array of 1 but the value directly.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated any will be removed in guzzlehttp/promises:2.0. Use Utils::any instead.
|
||||
*/
|
||||
function any($promises)
|
||||
{
|
||||
return Utils::any($promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that is fulfilled when all of the provided promises have
|
||||
* been fulfilled or rejected.
|
||||
*
|
||||
* The returned promise is fulfilled with an array of inspection state arrays.
|
||||
*
|
||||
* @see inspect for the inspection state array format.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated settle will be removed in guzzlehttp/promises:2.0. Use Utils::settle instead.
|
||||
*/
|
||||
function settle($promises)
|
||||
{
|
||||
return Utils::settle($promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an iterator that yields promises or values, returns a promise that is
|
||||
* fulfilled with a null value when the iterator has been consumed or the
|
||||
* aggregate promise has been fulfilled or rejected.
|
||||
*
|
||||
* $onFulfilled is a function that accepts the fulfilled value, iterator index,
|
||||
* and the aggregate promise. The callback can invoke any necessary side
|
||||
* effects and choose to resolve or reject the aggregate if needed.
|
||||
*
|
||||
* $onRejected is a function that accepts the rejection reason, iterator index,
|
||||
* and the aggregate promise. The callback can invoke any necessary side
|
||||
* effects and choose to resolve or reject the aggregate if needed.
|
||||
*
|
||||
* @param mixed $iterable Iterator or array to iterate over.
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated each will be removed in guzzlehttp/promises:2.0. Use Each::of instead.
|
||||
*/
|
||||
function each(
|
||||
$iterable,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return Each::of($iterable, $onFulfilled, $onRejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like each, but only allows a certain number of outstanding promises at any
|
||||
* given time.
|
||||
*
|
||||
* $concurrency may be an integer or a function that accepts the number of
|
||||
* pending promises and returns a numeric concurrency limit value to allow for
|
||||
* dynamic a concurrency size.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated each_limit will be removed in guzzlehttp/promises:2.0. Use Each::ofLimit instead.
|
||||
*/
|
||||
function each_limit(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return Each::ofLimit($iterable, $concurrency, $onFulfilled, $onRejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like each_limit, but ensures that no promise in the given $iterable argument
|
||||
* is rejected. If any promise is rejected, then the aggregate promise is
|
||||
* rejected with the encountered rejection.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated each_limit_all will be removed in guzzlehttp/promises:2.0. Use Each::ofLimitAll instead.
|
||||
*/
|
||||
function each_limit_all(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null
|
||||
) {
|
||||
return Each::ofLimitAll($iterable, $concurrency, $onFulfilled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated is_fulfilled will be removed in guzzlehttp/promises:2.0. Use Is::fulfilled instead.
|
||||
*/
|
||||
function is_fulfilled(PromiseInterface $promise)
|
||||
{
|
||||
return Is::fulfilled($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is rejected.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated is_rejected will be removed in guzzlehttp/promises:2.0. Use Is::rejected instead.
|
||||
*/
|
||||
function is_rejected(PromiseInterface $promise)
|
||||
{
|
||||
return Is::rejected($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled or rejected.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @deprecated is_settled will be removed in guzzlehttp/promises:2.0. Use Is::settled instead.
|
||||
*/
|
||||
function is_settled(PromiseInterface $promise)
|
||||
{
|
||||
return Is::settled($promise);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new coroutine.
|
||||
*
|
||||
* @see Coroutine
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*
|
||||
* @deprecated coroutine will be removed in guzzlehttp/promises:2.0. Use Coroutine::of instead.
|
||||
*/
|
||||
function coroutine(callable $generatorFn)
|
||||
{
|
||||
return Coroutine::of($generatorFn);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Don't redefine the functions if included multiple times.
|
||||
if (!function_exists('GuzzleHttp\Promise\promise_for')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
||||
Reference in new issue
Block a user