PHP 中的“ClosedGeneratorException”是什么?

In PHP, what is the `ClosedGeneratorException`?

在 PHP 7.0 和 7.1 中查看 get_declared_classes() 的输出时,我注意到 ClosedGeneratorException.

手册中没有 much mention of it and it does not seem to be listed on either the Predefined Exceptions or SPL exceptions 个条目。

甚至源代码也not hold much information about it

那么,什么是ClosedGeneratorException

(有什么用?什么时候出现?应该什么时候用?)

根据评论中的回复,我能够回答我自己的问题


code in the PHP core that throws this exception 状态:

    /* php-src/Zend/zend_generators.c */

    zend_throw_exception(
        zend_ce_ClosedGeneratorException,
        "Generator yielded from aborted, no return value available",
        0
    );

an article on airbrake.io进入ClosedGeneratorException的细节:

A ClosedGeneratorException occurs when attempting to perform a traversal on a generator that has already been closed or terminated.

换句话说,当生成器有运行个值时,请求一个新值会触发这个异常。(1)

基于 this test from the PHP core 我构建了两个场景,其中 ClosedGeneratorException 被抛出(并被捕获)。

通过从内部生成器中抛出异常(使用 yield from syntax)可以很容易地模拟这种行为。例外是 only 从 Generator 内部抛出。 (尽管它 可以 在生成器外捕获)。

下面附有两个场景。这两个例子都可以在ideone.com(2)(3)

上看到运行ning

两个例子的输出如下:

  • 在生成器中捕获 ClosedGeneratorException(2)

    Generator: 0
    1
    Generator: 1
    Caught ClosedGeneratorException
    
  • 在发电机外捕捉 ClosedGeneratorException(3)

    Generator: 0
    Caught Generic Exception
    Generator: 1
    Caught ClosedGeneratorException
    

脚注

  1. 文章提供了一个触发异常的示例,但该示例似乎不起作用(因为抛出了常规异常)。
  2. 在生成器中捕获 ClosedGeneratorExceptionhttps://ideone.com/FxTLe9
  3. 在发电机外捕捉 ClosedGeneratorExceptionhttps://ideone.com/ipEgKx

代码示例

在发电机中捕获 ClosedGeneratorException

<?php

class CustomException extends Exception {}

function from() {
    yield 1;
    throw new CustomException();
}

function gen($gen) {
    try {
        yield from $gen;
    } catch (\ClosedGeneratorException $e) {
        yield "Caught ClosedGeneratorException";
    } catch (\Exception $e) {
        yield "Caught Generic Exception";
    }
}

$gen = from();
$gens[] = gen($gen);
$gens[] = gen($gen);

foreach ($gens as $g) {
    $g->current(); // init.
}

foreach ($gens as $i => $g) {
    print "Generator: $i\n";
    print $g->current()."\n";
    $g->next();
}

在发电机外捕获 ClosedGeneratorException

<?php

class CustomException extends Exception {}

function from() {
    yield 1;
    throw new CustomException();
}

function gen($gen) {
    yield from $gen;
}

$gen = from();
$gens[] = gen($gen);
$gens[] = gen($gen);

foreach ($gens as $g) {
    $g->current(); // init.
}

foreach ($gens as $i => $g) {
    print "Generator: $i\n";
    try {
        $g->current();
        $g->next();
    } catch (\ClosedGeneratorException $e) {
        print "Caught ClosedGeneratorException\n";
    } catch (\Exception $e) {
        print "Caught Generic Exception\n";
    }
}