Trong PHP: sự khác biệt giữa lợi nhuận của hồi sinh, sản lượng của Google, sản lượng từ sự khác biệt và kết hợp cả năng suất và lợi nhuận trong cùng một chức năng là gì?


10

Sự khác biệt giữa returnyielddường như rõ ràng cho đến khi tôi nhận ra cũng có yield fromvà khả năng kết hợp cả hai returnyieldtrong cùng một chức năng!

Sự hiểu biết của tôi returnlà mọi thứ sau khi không được thực thi, phải không?

Tuy nhiên:

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

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

Sản xuất: "123"

Nhưng như sau:

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

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

Sản xuất không có gì! Vậy có nghĩa là năng suất được thực hiện?

Đây có phải là một lỗi?


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

Câu trả lời:


10

Return

Đơn giản chỉ cần trả lại một giá trị duy nhất cho người gọi.

Yield

Chuyển đổi hàm / phương thức hiện tại để trả về a Generator, sẽ tạo ra nhiều hơn một giá trị duy nhất: mỗi lần yieldđược kích hoạt, nó cung cấp giá trị cho người gọi, mỗi lần, theo cách truyền thống sử dụng một foreachvòng lặp.

Yield + Return

Các trình tạo, ngoài việc tạo các giá trị, cũng có thể, cung cấp một giá trị được trả về duy nhất. Giá trị đó sẽ không phải là một phần của vòng lặp xung quanh trình tạo, nó phải được truy cập bằng Generator::getReturn()phương thức.

Return + Yield

Điều này có thể được coi là một lỗi, tuy nhiên, nó không phải là.

Đó là hai giai đoạn:

  1. Từ mã đến mã byte : trong giai đoạn này, generate()hàm được xem là có chứa yieldtừ khóa, do đó nó được đánh dấu là tạo ra a Generator.
  2. Thực thi : Bởi vì returnxảy ra trước yield, máy phát điện không có cơ hội tạo ra bất kỳ giá trị nào. Tuy nhiên, [1, 2, 3]mảng có thể được lấy với Generator::getReturn().

Một ví dụ chú thích đầy đủ:

// 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
Ví dụ cuối cùng, trả về "kết thúc" việc thực thi hàm, nghĩa là mã không đạt được kết quả.
Rodrigo Jarouche

5

Từ tài liệu :

Bất kỳ chức năng có chứa yieldlà một chức năng tạo.

Vì vậy, không quan trọng việc yieldthực thi hay không, trình phân tích cú pháp sẽ nhìn thấy nó ở đâu đó trong định nghĩa hàm và biến nó thành một trình tạo.

Nếu hàm không bao giờ thực thi yieldcâu lệnh, thì trình tạo không tạo ra bất kỳ giá trị nào. Giá trị được trả về returnbị bỏ qua khi bạn cố gắng sử dụng kết quả. Các tài liệu nói:

Lưu ý:
Trong PHP 5, trình tạo không thể trả về giá trị: làm như vậy sẽ dẫn đến lỗi biên dịch. Một returncâu lệnh trống là cú pháp hợp lệ trong một trình tạo và nó sẽ chấm dứt trình tạo. Kể từ PHP 7.0, trình tạo có thể trả về các giá trị, có thể được truy xuất bằng Trình tạo :: getReturn () .

Vì vậy, bạn có thể làm:

$gen = generate();
foreach ($gen as $value) {
    echo $value;
}
print_r($gen->getReturn());
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.