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