mirror of
https://github.com/danog/amp.git
synced 2024-12-02 17:37:50 +01:00
Refactor Coroutine to use await()
Dropped polyfill, ext-fiber will be required to run any v3 code.
This commit is contained in:
parent
9f68bd4046
commit
b65823e0bb
@ -33,10 +33,10 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8"
|
"php": ">=8",
|
||||||
|
"ext-fiber": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-fiber": "*",
|
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"amphp/phpunit-util": "^1",
|
"amphp/phpunit-util": "^1",
|
||||||
"amphp/php-cs-fixer-config": "dev-master",
|
"amphp/php-cs-fixer-config": "dev-master",
|
||||||
@ -51,8 +51,7 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib/functions.php",
|
"lib/functions.php",
|
||||||
"lib/Internal/functions.php",
|
"lib/Internal/functions.php"
|
||||||
"polyfill/ext-fiber.php"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"autoload-dev": {
|
"autoload-dev": {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace Amp;
|
namespace Amp;
|
||||||
|
|
||||||
use React\Promise\PromiseInterface as ReactPromise;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated Use {@see await()} and ext-fiber to await promises.
|
||||||
|
*
|
||||||
* Creates a promise from a generator function yielding promises.
|
* Creates a promise from a generator function yielding promises.
|
||||||
*
|
*
|
||||||
* When a promise is yielded, execution of the generator is interrupted until the promise is resolved. A success
|
* When a promise is yielded, execution of the generator is interrupted until the promise is resolved. A success
|
||||||
@ -18,44 +18,6 @@ final class Coroutine implements Promise
|
|||||||
{
|
{
|
||||||
use Internal\Placeholder;
|
use Internal\Placeholder;
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to transform the non-promise yielded from the generator into a promise, otherwise returns an instance
|
|
||||||
* `Amp\Failure` failed with an instance of `Amp\InvalidYieldError`.
|
|
||||||
*
|
|
||||||
* @param mixed $yielded Non-promise yielded from generator.
|
|
||||||
* @param \Generator $generator No type for performance, we already know the type.
|
|
||||||
*
|
|
||||||
* @return Promise
|
|
||||||
*/
|
|
||||||
private static function transform(mixed $yielded, \Generator $generator): Promise
|
|
||||||
{
|
|
||||||
$exception = null; // initialize here, see https://github.com/vimeo/psalm/issues/2951
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (\is_array($yielded)) {
|
|
||||||
return Promise\all($yielded);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($yielded instanceof ReactPromise) {
|
|
||||||
return Promise\adapt($yielded);
|
|
||||||
}
|
|
||||||
|
|
||||||
// No match, continue to returning Failure below.
|
|
||||||
} catch (\Throwable $exception) {
|
|
||||||
// Conversion to promise failed, fall-through to returning Failure below.
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Failure(new InvalidYieldError(
|
|
||||||
$generator,
|
|
||||||
\sprintf(
|
|
||||||
"Unexpected yield; Expected an instance of %s or %s or an array of such instances",
|
|
||||||
Promise::class,
|
|
||||||
ReactPromise::class
|
|
||||||
),
|
|
||||||
$exception
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \Generator $generator
|
* @param \Generator $generator
|
||||||
* @psalm-param \Generator<mixed,Promise|ReactPromise|array<array-key,
|
* @psalm-param \Generator<mixed,Promise|ReactPromise|array<array-key,
|
||||||
@ -63,98 +25,21 @@ final class Coroutine implements Promise
|
|||||||
*/
|
*/
|
||||||
public function __construct(\Generator $generator)
|
public function __construct(\Generator $generator)
|
||||||
{
|
{
|
||||||
try {
|
$this->resolve(async(function () use ($generator): mixed {
|
||||||
$yielded = $generator->current();
|
$yielded = $generator->current();
|
||||||
|
|
||||||
if (!$yielded instanceof Promise) {
|
while ($generator->valid()) {
|
||||||
if (!$generator->valid()) {
|
try {
|
||||||
$this->resolve($generator->getReturn());
|
$value = await($yielded);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$yielded = self::transform($yielded, $generator);
|
|
||||||
}
|
|
||||||
} catch (\Throwable $exception) {
|
} catch (\Throwable $exception) {
|
||||||
$this->fail($exception);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param \Throwable|null $e Exception to be thrown into the generator.
|
|
||||||
* @param mixed $v Value to be sent into the generator.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*
|
|
||||||
* @psalm-suppress MissingClosureParamType
|
|
||||||
* @psalm-suppress MissingClosureReturnType
|
|
||||||
*/
|
|
||||||
$onResolve = function (?\Throwable $e, mixed $v) use ($generator, &$onResolve): void {
|
|
||||||
/** @var bool $immediate Used to control iterative coroutine continuation. */
|
|
||||||
static $immediate = true;
|
|
||||||
|
|
||||||
/** @var \Throwable|null $exception Promise failure reason when executing next coroutine step, null at all other times. */
|
|
||||||
static $exception;
|
|
||||||
|
|
||||||
/** @var mixed $value Promise success value when executing next coroutine step, null at all other times. */
|
|
||||||
static $value;
|
|
||||||
|
|
||||||
$exception = $e;
|
|
||||||
/** @psalm-suppress MixedAssignment */
|
|
||||||
$value = $v;
|
|
||||||
|
|
||||||
if (!$immediate) {
|
|
||||||
$immediate = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
try {
|
|
||||||
do {
|
|
||||||
if ($exception) {
|
|
||||||
// Throw exception at current execution point.
|
|
||||||
$yielded = $generator->throw($exception);
|
$yielded = $generator->throw($exception);
|
||||||
} else {
|
continue;
|
||||||
// Send the new value and execute to next yield statement.
|
}
|
||||||
|
|
||||||
$yielded = $generator->send($value);
|
$yielded = $generator->send($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$yielded instanceof Promise) {
|
return $generator->getReturn();
|
||||||
if (!$generator->valid()) {
|
}));
|
||||||
$this->resolve($generator->getReturn());
|
|
||||||
$onResolve = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$yielded = self::transform($yielded, $generator);
|
|
||||||
}
|
|
||||||
|
|
||||||
$immediate = false;
|
|
||||||
$yielded->onResolve($onResolve);
|
|
||||||
} while ($immediate);
|
|
||||||
|
|
||||||
$immediate = true;
|
|
||||||
} catch (\Throwable $exception) {
|
|
||||||
$this->fail($exception);
|
|
||||||
$onResolve = null;
|
|
||||||
} finally {
|
|
||||||
$exception = null;
|
|
||||||
$value = null;
|
|
||||||
}
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Loop::defer(static function () use ($e) {
|
|
||||||
throw $e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
$yielded->onResolve($onResolve);
|
|
||||||
|
|
||||||
unset($generator, $yielded, $onResolve);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
Loop::defer(static function () use ($e) {
|
|
||||||
throw $e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
if (!\extension_loaded('fiber')) {
|
|
||||||
require __DIR__ . '/../stubs/Awaitable.php';
|
|
||||||
require __DIR__ . '/../stubs/FiberScheduler.php';
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user