如何捕获生成器引发的异常并恢复迭代? [英] How to catch exception thrown from a generator and resume iteration?

查看:94
本文介绍了如何捕获生成器引发的异常并恢复迭代?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个生成器,它将值的集合传递到方法中并产生结果。调用的方法可能会返回异常。发生这种情况时,我希望该异常落入调用生成器以处理该异常的代码中,然后继续循环生成器。

I have a generator that passes a collection of values into a method and yields the result. The method that is called may return an exception. When this happens, I would like the exception to fall through to the code that calls the generator to handle the exception, and then continue looping the generator.

为了说明这一点,以下是生成器的示例,该生成器将产生 1 ,并抛出 \Exception ,然后产生 3

To illustrate this, the following is an example of generator that will yield 1, throw an \Exception, then yield 3.

/** @var \Generator $gen */
$gen = function () {
    for ($i = 1; $i <= 3; $i++) {
        if ($i == 2) {
            throw new \Exception('Exception thrown for 2');
        }

        yield $i;
    }
};

这是我尝试运行此代码以使它产生的示例。 > 3

This is an example of my attempt to run this code such that I can get it to yield 3

$g = $gen();

var_export($g->current());
echo "\n";

try {
    $g->next();
    var_export($g->current());
    echo "\n";
} catch (\Exception $e) {
    echo $e->getMessage() . "\n";
}

try {
    $g->next();
    var_export($g->current());
    echo "\n";
} catch (\Exception $e) {
    echo $e->getMessage() . "\n";
}

以下是上述代码的输出。

The following is the output of the above code.

1
Exception thrown for 2.
NULL

因此重复调用 next()不会执行任何操作,而 current()将返回 NULL ,在这里我希望生成器继续通过异常,这样我就可以得到 3

So a repeated calls to next() does nothing and current() will return NULL, where I would like the generator to continue past the Exception so I can get 3.

推荐答案

在生成器中抛出异常将其完全关闭,这就是为什么它在生成器上返回 NULL的原因第三次迭代。如果在引发异常后尝试 $ g-> valid(),则结果为 false

Throwing the exception inside generator is closing it totally, that is why it returns "NULL" on third iteration. If you try $g->valid() after throwing the exception you will get false as the result.

您应该处理生成器中的异常,甚至可以使用 $ g-> throw(< )方法。有关更多信息,请查看文档

You should handle the exceptions inside generator, you can even throw them inside generator using $g->throw() method. For more info check the documentation

但是,您可能要实现的目标。您可以 yield 例外,而不是抛出异常。这样,您将不会关闭生成器,并且可以在外部处理异常。

However, what you are trying to achieve is possible. You can yield the exception, instead of throwing. This way you will not close the generator, and can handle the exception outside.

尝试以下代码:

$gen = function () {
    for ($i = 1; $i <= 3; $i++) {
        // If something wrong happens
        if ($i == 2) {
            // Instead throwing the exception yield it
            // that way we don't close the generator
            yield new \Exception('Exception thrown for 2');
        } else {
            yield $i;
        }
    }
};

并对其进行测试:

$g = $gen();
for ($i = 0; $i < 3; $i++) {
  $current = $g->current();

  // Instead of catching, check if the yielded value is Exception
  if ($current instanceof \Exception) {
      // Handle the exception directly
      // or throw it with throw $current to handle it in normal try-catch block
      echo $current->getMessage() . "\n";
  } else {
      echo $current . "\n";
  }

  $g->next();
}

给出的结果是:

1
Exception thrown for 2
3

这篇关于如何捕获生成器引发的异常并恢复迭代?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆