X

Yield là gì trong PHP

Yield là gì?

Yield là một hàm Generator giống như một hàm bình thường, ngoại trừ việc thay vì trả về một giá trị, Generator sẽ mang lại nhiều giá trị như nó cần. Nhìn vào ví dụ sau để dễ hiểu nhé:

function getValues() {
    yield 'value';
}
// print the string "value"
echo getValues();

Tất nhiên, đây không phải là cách nó hoạt động, ví dụ trước sẽ cho bạn một lỗi nghiêm trọng: Không thể chuyển đổi đối tượng của lớp Trình tạo thành chuỗi, chúng ta hãy làm rõ hơn bên dưới đây.

Khác nhau giữa yield và return

Lỗi trước có nghĩa là hàm getValues ​​() không trả về một chuỗi như mong đợi, chúng ta hãy kiểm tra kiểu của nó:

function getValues() {
    return 'value';
}
var_dump(getValues()); // string(5) "value" đây là 1 string được trả về kiểu chuổi.

function getValues() {
    yield 'value';
}
var_dump(getValues()); // class Generator#1 (0) {} đây là 1 Object Generator được trả về từ 1 Class Generator.

Lớp Generator  triển khai giao diện Iterator, có nghĩa là bạn phải lặp qua hàm getValue () để có được các giá trị:

foreach (getValues() as $value) {
   echo $value;
}
// using variable is also alright
$values = getValues();
foreach ($values as $value) {
   echo $value;
}

Nhưng đây không phải là sự khác biệt duy nhất!

Generator cho phép bạn viết mã sử dụng foreach để lặp lại một tập hợp dữ liệu mà không cần xây dựng một mảng trong bộ nhớ, điều này có thể khiến bạn vượt quá giới hạn bộ nhớ. Quá tốt nếu bạn đang cần sử dụng loop lồng nhau rồi.

Trong ví dụ sau, chúng tôi sẽ xây dựng một mảng gồm 800.000 phần tử và trả về nó từ hàm getValues() , và trong khi đó, chúng ta sẽ lấy bộ nhớ được phân bổ cho tập lệnh này bằng cách sử dụng hàm memory_get_usage() , chúng ta sẽ sử dụng bộ nhớ sau mỗi 200.000 phần tử được thêm vào, có nghĩa là chúng ta sẽ đặt bốn điểm kiểm tra.

<?php
function getValues() {
   $valuesArray = [];
   // sử dụng bộ nhớ ban đầu
   echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
   for ($i = 1; $i < 800000; $i++) {
      $valuesArray[] = $i;
      // đo lường việc sử dụng bộ nhớ
      if (($i % 200000) == 0) {
         // sử dụng bộ nhớ tính bằng megabyte
         echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
      }
   }
   return $valuesArray;
}
$myValues = getValues(); // xây dựng mảng ở đây một khi chúng ta gọi hàm
foreach ($myValues as $value) {}

Điều đã xảy ra trong ví dụ trước là việc tiêu thụ bộ nhớ và đầu ra của tập lệnh này không:

0.34 MB
8.35 MB
16.35 MB
32.35 MB

Điều đó có nghĩa là tập lệnh vài dòng của chúng tôi đã tiêu thụ hơn 30 Megabyte bộ nhớ (Ôi trời ơi), mỗi khi bạn thêm một phần tử vào mảng $valueArray, bạn sẽ tăng kích thước của nó trong bộ nhớ. Chương trình càng loop nhiều thì càng dễ crash nhé. Giời hãy cùng LPTech thử với Yield xem như thế nào.

<?php
function getValues() {
   // get the initial memory usage
   echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
   for ($i = 1; $i < 800000; $i++) {
      yield $i;
      // let us do profiling, so we measure the memory usage
      if (($i % 200000) == 0) {
         // get memory usage in megabytes
         echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
      }
   }
}
$myValues = getValues(); // no action taken until we loop over the values
foreach ($myValues as $value) {} // start generating values here

Đầu ra của kịch bản này là đáng ngạc nhiên đến cả LPTech cũng giật mình:

0.34 MB
0.34 MB
0.34 MB
0.34 MB

Điều đó không có nghĩa là bạn chuyển từ biểu thức return thành yield, nhưng nếu bạn đang xây dựng các mảng lớn trong ứng dụng của mình, điều này gây ra các vấn đề về bộ nhớ trên máy chủ, thì yield phù hợp với trường hợp của bạn.

Tuỳ chọn của Yield là gì ?

Có nhiều lựa chọn cho yield, tôi sẽ làm nổi bật vài trong số chúng:

Sử dụng yield, bạn cũng có thể sử dụng return;

function getValues() {
   yield 'value';
   return 'returnValue';
}
$values = getValues();
foreach ($values as $value) {}
echo $values->getReturn(); // 'returnValue'

Trả về keys-values

function getValues() {
   yield 'key' => 'value';
}
$values = getValues();
foreach ($values as $key => $value) {
   echo $key . ' => ' . $value;
}

Kết luận

Lý do chính của chủ đề này của LPTech là để làm rõ sự khác biệt giữa yieldreturn đặc biệt về bộ nhớ, hiển thị một số ví dụ vì tôi thấy nó thực sự quan trọng đối với bất kỳ lập trình viên nào đang đi theo hướng thiết kế website

Tài liệu tham khảo

http://php.net/manual/en/language.generators.syntax.php
http://php.net/manual/en/class.generator.php
http://php.net/manual/en/language.generators.php
http://php.net/manual/en/function.memory-get-usage.php