Generator 구문

생성기 함수는 값을 반환하는 대신 생성기가 필요한 만큼 많은 값을 생성한다는 점을 제외하고는 일반 함수처럼 보입니다. yield를 포함하는 모든 함수는 생성기 함수입니다.

생성기 함수가 호출되면 반복될 수 있는 객체를 반환합니다. 해당 객체를 반복할 때(예: foreach 루프를 통해), PHP는 값이 필요할 때마다 객체의 반복 메서드를 호출한 다음 생성기가 값을 생성할 때 생성기의 상태를 저장하여 다음과 같은 경우 다시 시작할 수 있습니다. 다음 값이 필요합니다.

더 이상 생성할 값이 없으면 생성기가 종료될 수 있으며 호출 코드는 배열에 값이 부족한 것처럼 계속됩니다.

메모: Generator는 Generator::getReturn()을 사용하여 검색할 수 있는 값을 반환할 수 있습니다.


yield keyword

생성기 함수의 핵심은 yield 키워드입니다. 가장 간단한 형태에서 yield 문은 함수 실행을 중지하고 반환하는 대신 생성기를 통해 반복되는 코드에 값을 제공하고 생성기 함수의 실행을 일시 중지한다는 점을 제외하면 return 문과 매우 유사합니다.

예제 #1 값을 산출하는 간단한 예

                  
<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        // Note that $i is preserved between yields.
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}
?>
                  
                

위의 예는 다음을 출력합니다.

1
2
3
                

메모: 내부적으로 순차 정수 키는 비연관 배열과 마찬가지로 생성된 값과 쌍을 이룹니다.

주의 $data에 할당될 값은 Generator::send()에 전달된 값이거나 대신 Generator::next()가 호출되는 경우 null입니다.


키로 값 산출

PHP는 연관 배열도 지원하며 제너레이터도 다르지 않습니다. 위와 같이 간단한 값을 생성하는 것 외에도 키를 동시에 생성할 수도 있습니다.

키/값 쌍을 생성하는 구문은 아래와 같이 연관 배열을 정의하는 데 사용되는 구문과 매우 유사합니다.

예제 #2 키/값 쌍 생성

                  
<?php
/*
 * The input is semi-colon separated fields, with the first
 * field being an ID to use as a key.
 */

$input = <<<'EOF'
1;PHP;Likes dollar signs
2;Python;Likes whitespace
3;Ruby;Likes blocks
EOF;

function input_parser($input) {
    foreach (explode("\n", $input) as $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);

        yield $id => $fields;
    }
}

foreach (input_parser($input) as $id => $fields) {
    echo "$id:\n";
    echo "    $fields[0]\n";
    echo "    $fields[1]\n";
}
?>
                  
                

위의 예는 다음을 출력합니다.

1:
    PHP
    Likes dollar signs
2:
    Python
    Likes whitespace
3:
    Ruby
    Likes blocks
                

주의 이전에 표시된 단순 값 산출과 마찬가지로 표현식 컨텍스트에서 키/값 쌍을 산출하려면 yield 문을 괄호로 묶어야 합니다.

$data = (yield $key => $value);


null 값 생성

Yield는 인수 없이 호출되어 자동 키가 있는 null 값을 생성할 수 있습니다.

예제 #3 null을 반환

                  
<?php
function gen_three_nulls() {
    foreach (range(1, 3) as $i) {
        yield;
    }
}

var_dump(iterator_to_array(gen_three_nulls()));
?>
                  
                

위의 예는 다음을 출력합니다.

array(3) {
  [0]=>
  NULL
  [1]=>
  NULL
  [2]=>
  NULL
}
                

Yielding by reference

생성기 함수는 값뿐만 아니라 참조로도 값을 산출할 수 있습니다. 이것은 함수에서 참조를 반환하는 것과 같은 방식으로 수행됩니다. 함수 이름 앞에 앰퍼샌드를 추가합니다.

예제 #4 null을 반환

                  
<?php
function &gen_reference() {
    $value = 3;

    while ($value > 0) {
        yield $value;
    }
}

/*
 * Note that we can change $number within the loop, and
 * because the generator is yielding references, $value
 * within gen_reference() changes.
 */
foreach (gen_reference() as &$number) {
    echo (--$number).'... ';
}
?>
                  
                

위의 예는 다음을 출력합니다.

2... 1... 0...
                

Generator delegation via yield from

생성기 위임을 사용하면 yield from 키워드를 사용하여 다른 생성기, Traversable 개체 또는 배열에서 값을 생성할 수 있습니다. 그런 다음 외부 생성기는 내부 생성기, 개체 또는 배열이 더 이상 유효하지 않을 때까지 모든 값을 산출하고 그 후에는 외부 생성기에서 실행이 계속됩니다.

생성기가 yield from과 함께 사용되는 경우 yield from 표현식은 내부 생성기에서 반환된 값도 반환합니다.

주의
배열에 저장(예: iterator_to_array() 사용)

yield from은 키를 재설정하지 않습니다. Traversable 개체 또는 배열에서 반환된 키를 유지합니다. 따라서 일부 값은 배열에 삽입할 때 해당 키로 이전 값을 덮어쓰는 다른 yield 또는 yield from과 공통 키를 공유할 수 있습니다.

이것이 중요한 일반적인 경우는 기본적으로 키 배열을 반환하는 iterator_to_array()로 예상치 못한 결과를 초래할 수 있습니다. iterator_to_array()에는 두 번째 매개변수 use_keys가 있습니다. 이 매개변수는 false로 설정하여 Generator에서 반환된 키를 무시하면서 모든 값을 수집할 수 있습니다.

예제 #5 iterator_to_array()로 산출

                    
  <?php
  function inner() {
      yield 1; // key 0
      yield 2; // key 1
      yield 3; // key 2
  }
  function gen() {
      yield 0; // key 0
      yield from inner(); // keys 0-2
      yield 4; // key 1
  }
  // pass false as second parameter to get an array [0, 1, 2, 3, 4]
  var_dump(iterator_to_array(gen()));
  ?>
                    
                  

위의 예는 다음을 출력합니다.

  array(3) {
  [0]=>
  int(1)
  [1]=>
  int(4)
  [2]=>
  int(3)
}
                  

예제 #6 yield의 기본 사용

                  
<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    yield 9;
    yield 10;
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

foreach (count_to_ten() as $num) {
    echo "$num ";
}
?>
                  
                

위의 예는 다음을 출력합니다.

1 2 3 4 5 6 7 8 9 10
                

예제 #7 yield from and return values

                  
<?php
function count_to_ten() {
    yield 1;
    yield 2;
    yield from [3, 4];
    yield from new ArrayIterator([5, 6]);
    yield from seven_eight();
    return yield from nine_ten();
}

function seven_eight() {
    yield 7;
    yield from eight();
}

function eight() {
    yield 8;
}

function nine_ten() {
    yield 9;
    return 10;
}

$gen = count_to_ten();
foreach ($gen as $num) {
    echo "$num ";
}
echo $gen->getReturn();
?>
                  
                

위의 예는 다음을 출력합니다.

1 2 3 4 5 6 7 8 9 10