拆分PHP生成器

时间:2014-10-31 18:08:03

标签: php iterator generator

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

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 );
        }
    }
}

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

1 个答案:

答案 0 :(得分: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。;)