итератор — расщепление генераторов 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 );
}
}
}

Можно ли как-то избежать необходимости добавлять этот цикл, сохраняя при этом поведение генератора и правильно разделяя метод? Я раньше не использовал генераторы, поэтому, возможно, упускаю что-то очевидное.

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 / генератор-гнездо

При использовании этого пакета вы просто получаете генераторы и оборачиваете исходный вызов генератора методом, предоставляемым пакетом.

use Hedronium\GeneratorNest\GeneratorNest;

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

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

Я бы посоветовал вам взглянуть на источник, чтобы понять, что на самом деле происходит. Это только 28 строк.;)

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]