PHP에서 : "return", "yield", "yield from"과 같은 함수에서 yield와 return을 혼합하는 것의 차이점은 무엇입니까?


10

의 차이 return와는 yield내가 거기에 또한이었다 알아 냈까지 명확 보였다 yield from과 가능성을 모두 결합 return하고 yield바로 그 기능에!

내 이해는 return이후의 모든 것이 실행 되지 않았다는 것입니다 .

하나:

function generate(): iterable {
    return [1, 2, 3];
}

foreach (generate() as $value) {
    echo $value;
}

생산 : "123"

그러나 다음은

function generate(): iterable {
    return [1, 2, 3];
    yield;
}

foreach (generate() as $value) {
    echo $value;
}

아무것도 생산하지 않습니다! 그래서 수율이 실행된다는 의미입니까?

이것이 버그입니까?


1
var_dump(generate()->GetReturn());
AbraCadaver

답변:


10

Return

단순히 발신자에게 고유 한 가치를 제공합니다.

Yield

현재 함수 / 메소드를 변환하여을 반환하면 Generator고유 한 값 이상을 생성합니다. 매번 yield트리거 될 때마다 전통적으로 foreach루프를 사용하여 한 번에 하나씩 호출자에게 값을 제공합니다 .

Yield + Return

생성기는 값을 생성 할뿐만 아니라 고유 한 반환 값을 제공 할 수도 있습니다. 이 값은 생성기 주변의 루프의 일부가 아니며 Generator::getReturn()메소드를 사용하여 액세스해야합니다 .

Return + Yield

이것은 버그로 볼 수 있지만 그렇지 않습니다.

그들은 두 단계입니다 :

  1. 코드에서 바이트 코드로 :이 단계에서 generate()함수는 yield키워드 를 포함하는 것으로 보이 므로을 생성하는 것으로 표시됩니다 Generator.
  2. 실행 :이 return발생하기 전에 발생하기 때문에 yield생성기에서 값을 생성 할 기회가 없습니다. 그러나을 사용하여 [1, 2, 3]배열을 검색 할 수 있습니다 Generator::getReturn().

주석이 달린 완전한 예 :

// Generate integers 1 and 2
function generateIntegers1And2(): Generator {
    yield 1;                                  // <--+   <--+   <--+
    yield 2;                                  //  <-+    <-+    <-+
}                                             //    |      |      |
                                              //    |      |      |
foreach (generateIntegers1And2() as $value) { //    |      |      |
    var_dump($value); // Shows 1, then 2          ->*      |      |
}                                                       // |      |
                                                        // |      |
function generateOuterYield(): Generator {              // |      |
    // Yields the generator *itself* returned by           |      |
    // generateIntegers1And2() not the actual values       |      |
    // generated by it.                                    |      |
    // This means we are producing here a generator        |      |
    // of generator of integers.                           |      |
    yield generateIntegers1And2();          // <-+         |      |
}                                             // |         |      |
                                              // |         |      |
foreach (generateOuterYield() as $value) {    // |         |      |
    var_dump($value);                       // ->*         |      |
    // The two levels of imbrication means we have         |      |
    // to loop once more to actually consume               |      |
    // generateIntegers1And2                               |      |
    foreach ($value as $val) {                          // |      |
        var_dump($val); // Shows 1, then 2               ->*      |
    }                                                          // |
}                                                              // |
                                                               // |
// A generator can just be returned as-is:                        |
function generateOuterReturn(): Generator {                    // |
    return generateIntegers1And2();                            // |
}                                                              // |
                                                               // |
// it doesn't change the way it is consumed                       |
foreach (generateOuterReturn() as $value) {                    // |
    var_dump($value); // Shows 1, then 2                          |
}                                                              // |
                                                               // |
function generateOuterYieldFrom(): Generator {                 // |
    // First yield values generated by generateIntegers1And2()    |
    yield from generateIntegers1And2();                        // *<---+
    // then yield integers 3                                           |
    yield 3;                                                     // <--+
    // and 4                                                           |
    yield 4;                                                     //  <-+
}                                                                //    |
                                                                 //    |
foreach (generateOuterYieldFrom() as $value) {                   //    |
    var_dump($value); // Shows 1, 2, 3 and 4                         ->*
}

function generateIntegers56AndReturn(): Generator {
    yield 5;                                                  // <---+
    yield 6;                                                  //  <--+
                                                              //     |
    return ["five", "six"];                       // <--+            |
}                                                 //    |            |
                                                  //    |            |
$gen = generateIntegers56AndReturn();             //    |            |
                                                  //    |            |
// Consume the values **yielded** by                    |            |
// generateIntegers56AndReturn()                        |            |
foreach ($gen as $value) {                        //    |            |
    var_dump($value); // Shows 5, then 6                |          ->*
}                                                 //    |
                                                  //    |
// Access the value **returned** by the generator       |
var_dump($gen->getReturn());                      //  ->*

function wtf(): Generator {
    return ["W", "T", "F", "!"];
    // Without the following line, PHP would complain with a TypeError:
    // Return value of wtf() must be an instance of Generator, array returned.
    // The presence of a yield keyword anywhere inside the function makes it a Generator.
    // However, since we return *before* reaching any *yield*, 42 is never yielded.
    // This is empty generator!
    yield 42;
}

$gen = wtf();

// This foreach loop is not entered!
foreach ($gen as $value) {
    var_dump($value);
}

// However, we can loop on the array *returned* by wtf():
foreach ($gen->getReturn() as $value) {
    echo $value; // Will print: WTF!
}

1
마지막 예에서, 리턴은 함수 실행을 "종료"합니다. 즉, 코드가 yeld를 달성하지 못합니다.
Rodrigo Jarouche

5

로부터 문서 :

포함하는 모든 함수 yield는 생성기 함수입니다.

따라서 yield실행 여부는 중요하지 않으며 파서는 함수 정의의 어딘가에서이를 생성기로 변환합니다.

함수가 yield명령문을 실행 하지 않으면 생성기가 값을 생성하지 않습니다. return결과를 사용하려고하면 반환 된 값 이 무시됩니다. 설명서는 다음과 같이 말합니다.

참고 :
PHP 5에서 생성기는 값을 반환 할 수 없습니다. 그렇게하면 컴파일 오류가 발생합니다. 빈 return명령문은 생성기 내에서 유효한 구문이며 생성기를 종료합니다. PHP 7.0부터 Generator는 Generator :: getReturn ()을 사용하여 검색 할 수있는 값을 반환 할 수 있습니다 .

그래서 당신은 할 수 있습니다 :

$gen = generate();
foreach ($gen as $value) {
    echo $value;
}
print_r($gen->getReturn());
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.