PHP Generator::throw() 方法用于手动引发生成器的一个异常。
( PHP 5 >= 5.5.0, PHP 7 )
这个方法就有意思了,使用 Generator::throw() 方法,我们可以在外部生成一个异常,并将该已成发送给生成器,生成器会在下次遇到 yield 语句时触发这个异常。
方法原型
PHP Generator::throw() 方法的原型如下
public mixed Generator::throw ( Throwable $exception )
从原型中可以看出,该方法接收一个异常 $exception ,并将异常发送给生成器,并继续执行生成器。(因为生成器需要下次遇到 yield 时才会触发这个异常 )。
这个方法的行为和在生成器内部使用 throw $exception 语句替换当前 yield 表达式时的行为相同。
如果在调用此方法时生成器已关闭,则异常将在调用者的上下文中抛出。
参数说明
参数
说明
$exception
要发送给生成器的异常
返回值
该方法返回已经 yield 的值。
你不是不很奇怪为什么还会返回一个值? 难道不是调用就会立即触发异常么 ?
前面章节我忘记说了,生成器看起来是在另一个线程中异步执行的代码。一旦执行,如果要停下来,只能是再次碰到 yield 语句。
范例一
简单的生成一个异常,并将该异常发送给生成器
function gen() {
echo "Foo\n";
try {
yield;
} catch (Exception $e) {
echo "Exception:{$e->getMessage()}\n";
}
echo "Bar\n";
}
$gen = gen();
$gen->throw(new Exception('Test'));
运行结果如下
Foo
Exception: Test
Bar
上面这段代码,当调用 gen() 创建一个生成器时并不会执行任何生成器内的函数。直到调用 $gen->throw(new Exception('Test')); 将一个异常发送给这个生成器。
因为该函数同时会触发生成器的执行,所以,就会开始输出 Foo ,但运行到 yield 时发现就要抛出一个异常,于是就会抛出一个异常,抛出的异常会被 try catch 捕获到,于是会输出 Exception: Test ,然后函数继续执行,就会输出 Bar
范例二
在上面这个范例中,yield 语句并没有生成一个值,我们看看如果生成了一个值的会是什么结果
function gen() {
echo "Foo\n";
for ( $i = 0; $i < 10; $i++ )
{
try {
echo $i,"\n";
yield $i;
} catch (Exception $e) {
echo "Exception:{$e->getMessage()}\n";
}
}
echo "Bar\n";
}
$gen = gen();
$ret = $gen->throw(new Exception('Test'));
echo $ret,"\n";
运行结果如下
Foo
0
Exception: Test
1
1
是不是对执行结果感到很疑惑 ?
首先,要记牢一件事:生成器只有运行到一个 yield 语句时才会停止执行。
所以当调用 $gen->throw(new Exception('Test')); 会触发生成器的执行,这会一路输出 Foo 和 0 。但是,当执行到 yield 0 时需要触发异常,所以这时候 yield 语句并不会暂停执行,而是继续执行,直到捕获异常,输出 Exception: Test,然后进行下一次迭代,输出 1 然后碰到 yield 1,这时候就会暂停执行了,因为 yield 1 的返回就是 1 ,所以,结果就像输出的那样了。