2014-10-31 4 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); 
     } 
    } 
} 

Но, конечно, я не могу просто вернуть результат этой новой функции, поскольку она также является генератором. (И я хочу, чтобы генератор, поэтому работа выполняется только тогда, когда запрашивается значение.) То, что я сделал, чтобы сделать эту работу, добавив еще одну петлю, внутри тела, если условие:

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) as $ flattened) { yield $ flattened; } 'loop с простым' yield $ this-> getFlattenedElement ($ element); 'Попробуйте! Ваш цикл обрабатывается генератором 'getFlattenedElement()' –

+0

Я пробовал это, но тогда мой тест не прошел, поэтому он определенно не эквивалентен. Если я это сделаю, он даст генератор и, следовательно, будет иметь результат типа «Генератор» нет? –

+0

Ну нет причин, почему это не должно работать: он не должен давать генератор, но должен давать результат от генератора .... рекурсивные генераторы работают –

ответ

1

То, что вы на самом деле пытаетесь сделать, называется делегированием генератора, и теперь это стало вопросом PHP-версии. Только PHP версии 7 и выше делегирования поддержки генератора и это выглядит следующим образом:

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

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

Это даст вам точно желаемый эффект или «рекурсивный» или «вложенных» или «делегировал» генератор вызовов. Но теперь проблема в PHP7. PHP 7 не работает. Для этого вам нужно будет написать еще один генератор, который принимает генератор, который дает генераторы. Как конвертер.

Я не буду вставлять код на здесь, но я недавно столкнулся с этой проблемой, которая заставила меня написать пакет, чтобы сделать именно это в 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.;) .;)

Смежные вопросы