Amphp之协程
协程是可中断的函数。在 PHP 中,它们可以使用生成器来实现。
虽然生成器通常用于使用 yield 关键字实现简单的迭代器和产生元素,但 Amp 使用 yield 作为中断点。当协程产生一个值时,协程的执行会暂时中断,允许运行其他任务,例如 I/O 处理程序、计时器或其他协程。
// 使用 Artax 获取资源并返回其主体。
$promise = Amp\call(function () use ($http) {
try {
// Yield control until the generator resolves
// and return its eventual result.
$response = yield $http->request("https://example.com/");
$body = yield $response->getBody();
return $body;
} catch (HttpException $e) {
// If promise resolution fails the exception is
// thrown back to us and we handle it as needed.
}
});
每次产生一个 Promise 时,协程都会订阅该 Promise,并在 Promise 解决后自动继续它。成功解析后,协程将使用 Generator::send()将解析值发送到生成器。如果失败,它将使用 Generator::throw()将异常抛出到生成器中。这允许编写几乎像同步代码一样的异步代码。
请注意,无需注册回调即可使用 Promise,并且可以使用普通的 catch 子句处理错误,如果未捕获到调用上下文,它将以与同步代码中异常冒泡的相同方式冒泡。
使用
Amp\call()始终从您的公共 API 返回一个承诺,而不是一个\Generator。生成器是不应该泄露给 API 使用者的实现细节。
Yield特性(Yield Behavior)
协程中的所有 yield 必须是以下三种类型之一:
| Yieldable | Description |
|---|---|
| Amp\Promise | 任何 Promise 实例都可能被产生,一旦 Promise 解决,控制权将返回给协程。如果解析失败,相关异常将被抛出到生成器中,并且必须由应用程序处理,否则它将冒泡。如果解析成功,则将 promise 的解析值发送回生成器。 |
| React\Promise\PromiseInterface | 与 Amp\Promise 相同。任何 React Promise 都会自动适应 Amp Promise。 |
| array | 产生一组 promise 使用 Amp\Promise\all() 隐式组合它们。元素不是 promise 的数组将导致 Amp\InvalidYieldError。 |
Yield vs. Yield From
yield用于“await”promise,yield from可用于委托给子例程。
yield from应该只用于委托给私有方法,任何公共 API 应该总是返回 Promise 而不是生成器。
当从 \Generator 中产生一个 Promise 时,\Generator 将暂停并在 Promise 解决后立即继续。使用 yield from产生另一个 \Generator。
除了使用 yield from,你还可以使用 yield new Coroutine($this->bar());或 yield call([$this, "bar"]);。
示例:
class Foo
{
public function delegationWithCoroutine(): Amp\Promise
{
return new Amp\Coroutine($this->bar());
}
public function delegationWithYieldFrom(): Amp\Promise
{
return Amp\call(function () {
return yield from $this->bar();
});
}
public function delegationWithCallable(): Amp\Promise
{
return Amp\call([$this, 'bar']);
}
public function bar(): Generator
{
yield new Amp\Success(1);
yield new Amp\Success(2);
return yield new Amp\Success(3);
}
}
Amp\Loop::run(function () {
$foo = new Foo();
$r1 = yield $foo->delegationWithCoroutine();
$r2 = yield $foo->delegationWithYieldFrom();
$r3 = yield $foo->delegationWithCallable();
var_dump($r1);
var_dump($r2);
var_dump($r3);
});
输出:
int(3)
int(3)
int(3)
有关 yield from 的更多信息,请参阅 PHP 手册。

1万+

被折叠的 条评论
为什么被折叠?



