2014-10-31 55 views
1

我刚刚写了一个生成器的一部分,并达到了正确运行的地步,但需要进行一些重构。该方法的结构如下:拆分PHP生成器

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

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

+0

为什么不消除'foreach($ this-> getFlattenedElement($ element)$ flattened){ yield $ flattened; } '带一个简单的'yield $ this-> getFlattenedElement($ element)''试试看!你的循环是由'getFlattenedElement()'生成器处理的 – 2014-10-31 18:37:41

+0

我试过了,但是然后我的测试失败了,所以它绝对不是等价的。如果我这样做,它会产生发电机,从而产生'Generator'类型的结果? – 2014-10-31 18:40:31

+0

那么它没有理由不应该工作:它不应该产生发电机,但应该产生发电机的结果....递归发电机做的工作 – 2014-10-31 18:45:03

回答

1

你实际上想做的事情就是所谓的Generator委托,现在它已经成为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;)