PHP में: "वापसी", "उपज", "से उपज" और दोनों उपज को मिलाने और एक ही फ़ंक्शन में वापस आने के बीच क्या अंतर है?


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
अंतिम उदाहरण, फ़ंक्शन निष्पादन को "समाप्त" करता है, अर्थात्, कोड येल्ड प्राप्त नहीं करता है।
रॉड्रिगो जारोच

5

से प्रलेखन :

कोई भी फंक्शन जिसमें yieldजनरेटर फंक्शन होता है।

तो यह कोई फर्क नहीं पड़ता कि क्या yieldनिष्पादित किया गया है, पार्सर इसे फ़ंक्शन परिभाषा में कहीं देखता है और इसे जनरेटर में बदल देता है।

यदि फ़ंक्शन yieldस्टेटमेंट को कभी निष्पादित नहीं करता है , तो जनरेटर किसी भी मूल्य का उत्पादन नहीं करता है। returnजब आप परिणाम का उपयोग करने का प्रयास करते हैं, तो लौटाए गए मान को अनदेखा कर दिया जाता है। प्रलेखन कहता है:

नोट:
PHP 5 में, एक जनरेटर एक मान नहीं लौटा सकता: ऐसा करने से एक संकलन त्रुटि हो जाएगी। एक खाली returnबयान एक जनरेटर के भीतर वैध वाक्यविन्यास था और यह जनरेटर को समाप्त कर देगा। PHP 7.0 के बाद, एक जनरेटर मानों को वापस कर सकता है, जिसे जनरेटर :: getReturn () का उपयोग करके पुनर्प्राप्त किया जा सकता है ।

तो आप कर सकते हैं:

$gen = generate();
foreach ($gen as $value) {
    echo $value;
}
print_r($gen->getReturn());
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.