【问题标题】:Splitting PHP generators拆分 PHP 生成器
【发布时间】:2014-10-31 18:08:02
【问题描述】:

我刚刚编写了生成器的一部分,并达到了它可以正常运行的地步,但需要进行一些重构。该方法的结构如下:

public function getFlattenedList( array $elements ) {
    foreach ( $elements as $element ) {
        if ( $this->someCondition( $element ) ) {
            // A pile of stuff here

            if ( $anotherCondition ) {
                for ( $i = 0; $i < $this->someValue(); $i++ ) {
                    yield $this->anotherOperation( $element );
                }
            }
        }
        else {
            yield $this->someOperation( $element );
        }
    }
}

这种方法是大/复杂的。最明显的做法是将 if 分支的主体移到它自己的方法中。像这样的

public function getFlattenedList( array $elements ) {
    foreach ( $elements as $element ) {
        if ( $this->someCondition( $element ) ) {
            // ???
            $this->getFlattenedElement( $element );
        }
        else {
            yield $this->someOperation( $element );
        }
    }
}

private function getFlattenedElement() {
    // A pile of stuff here

    if ( $anotherCondition ) {
        for ( $i = 0; $i < $this->someValue(); $i++ ) {
            yield $this->anotherOperation( $element );
        }
    }
}

当然我不能只返回这个新函数的结果,因为它也是一个生成器。 (而且我希望它是一个生成器,所以只有在请求值时才完成工作。)我所做的是在 if 条件的主体内添加另一个循环:

public function getFlattenedList( array $elements ) {
    foreach ( $elements as $element ) {
        if ( $this->someCondition( $element ) ) {
            foreach ( $this->getFlattenedElement( $element ) as $flattened ) {
                yield $flattened;
            }
        }
        else {
            yield $this->someOperation( $element );
        }
    }
}

是否有可能避免添加该循环,同时保持生成器行为并很好地拆分方法?我以前没有使用过生成器,所以可能会遗漏一些明显的东西。

【问题讨论】:

  • 为什么不使用简单的yield $this-&gt;getFlattenedElement( $element ); 消除foreach ( $this-&gt;getFlattenedElement( $element ) as $flattened ) { yield $flattened; } 循环试试看! getFlattenedElement() 生成器正在处理您的循环
  • 我试过这个,但后来我的测试失败了,所以它绝对不等价。如果我这样做,它将产生生成器,因此会产生Generator no? 类型的结果?
  • 好吧,它没有理由不工作:它不应该产生生成器,但应该产生生成器的结果......递归生成器确实工作
  • 如果我在公共生成器的结果上调用iterator_to_array,数组最终会包含生成器实例。 [ ResultClass 0, Generator, ResultClass 3 ] 而不是 [ ResultClass 0, ResultClass 1, ResultClass 2, ResultClass 3 ]。这不是我想要的。

标签: php iterator generator


【解决方案1】:

您实际上正在尝试做的是生成器委托,现在它已成为 PHP 版本的问题。只有 PHP 7 及更高版本支持生成器委托,它看起来像这样:

function gen_y() {
    yield 1;
    yield 2;
}

function gen_x() {
    yield from gen_y();
    yield from gen_y();
}

这将为您提供所需的效果或“递归”或“嵌套”或“委托”生成器调用。但现在的问题是 PHP7。没有多少生产环境运行 PHP7。为此,您需要编写另一个生成器,该生成器采用生成生成器的生成器。就像一个转换器。

我不会将代码粘贴到这里,但我最近遇到了这个问题,这迫使我在 PHP5 中编写了一个包来执行此操作:hedronium/generator-nest

使用此包时,您只需生成生成器,并使用包提供的方法包装初始生成器调用。

use Hedronium\GeneratorNest\GeneratorNest;

function gen_x() {
    yield gen_y();
    yield gen_y();
}

foreach (GeneratorNest::nested(gen_x()) as $x) {
    // Your Code.
}

我鼓励您查看源代码以了解实际情况。我是only 28 lines.;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多