Quay lại
Sử dụng Lazy Collections trong Laravel

Laravel team đã phát hành phiên bản 6.0 của framework và cùng với đó, họ đã thêm một loạt các tính năng mới thú vị. Trong số đó, mình sẽ nói về Lazy Collections trong bài viết này. Trong Laravel, lớp Illuminate\Support\Collection cung cấp một trình wrapper (bao bọc) thuận tiện để làm việc với các mảng dữ liệu. Mặt khác, tất cả các truy vấn Eloquent luôn được trả về dưới dạng các phiên bản Collection . LazyCollection về cơ bản mở rộng các tính năng của lớp Collection . Hãy nói về chúng một cách chi tiết.

LazyCollection là gì ?

Lớp LazyCollection giống như lớp Illuminate\Support\Collection nhưng nó nâng cấp hơn một chút. Về cơ bản, lớp này sử dụng các PHP generators (trình tạo PHP) để cho phép bạn làm việc với các bộ dữ liệu rất lớn trong khi vẫn giữ mức sử dụng bộ nhớ thấp

Về cơ bản, Generators giống như các hàm bình thường trong PHP nhưng thay vì trả về một giá trị, chúng mang lại bao nhiêu giá trị cần thiết. Vì vậy, bất kỳ chức năng nào có chứa “yield” là một Generators . Nó giống như trả về giá trị từ một hàm trong “realtime” và bạn không cần duy trì trạng thái của các giá trị trong chính hàm đó. Và một khi không còn giá trị nào được tạo ra, thì Generators có thể chỉ cần thoát ra và code sẽ tiếp tục được gọi giống như thể một mảng đã hết giá trị.

LazyCollection tận dụng hành vi này của các Generators để giữ cho bộ nhớ ở mức thấp trong khi làm việc với các bộ dữ liệu lớn một cách hiệu quả. Trích dẫn ví dụ từ tài liệu của Laravel, bạn có thể sử dụng LazyCollection trong các tình huống mà bạn cần xử lý các tệp thực sự lớn đồng thời ngăn cảnh báo hết bộ nhớ. Ở đây, chúng ta có thể phân tích cú pháp, chẳng hạn như một file log thực sự lớn, sử dụng LazyCollection kết hợp với lớp Collection truyền thống. Tại đây, thay vì đọc toàn bộ tệp vào bộ nhớ cùng một lúc, LazyCollection có thể được sử dụng để chỉ giữ một phần nhỏ của tệp trong bộ nhớ tại một thời điểm nhất định.

use App\LogEntry;
use Illuminate\Support\LazyCollection;

LazyCollection::make(function () {
    $handle = fopen('log.txt', 'r');

    while (($line = fgets($handle)) !== false) {
        yield $line;
    }
})->chunk(4)->map(function ($lines) {
    return LogEntry::fromLines($lines);
})->each(function (LogEntry $logEntry) {
    // Process the log entry...
});

Như bạn có thể thấy ở trên, LazyCollection::make là nơi chúng ta đã viết logic đọc dòng của file. Lưu ý, hàm ẩn danh mà chúng ta đã pass để tạo là một Generators  "yields", dòng (và sẽ trả về một đối tượng Generators  có thể lặp lại bằng các vòng lặp thông thường) cho phương thức chunk Collection  tiếp theo và từ đó trở đi, nó sẽ được xử lý thành mỗi collection method cuối cùng.

Using LazyCollection trong Eloquent models

Chúng ta có thể sử dụng query builder’s cursor trên model instance, về cơ bản trả về một LazyCollection instance . Hãy kiểm tra việc triển khai phương thức cursor.

public function cursor()
{
    if (is_null($this->columns)) {
        $this->columns = ['*'];
    }

    return new LazyCollection(function () {
        yield from $this->connection->cursor(
            $this->toSql(), $this->getBindings(), ! $this->useWritePdo
        );
    });
}

Như bạn có thể thấy, trả về một LazyCollection sẽ cho phép chúng ta xử lý kết quả của một cursor giống như một Collection instance thông thường. Điều này cho phép chúng ta vẫn chỉ chạy một truy vấn đối với cơ sở dữ liệu nhưng cũng chỉ giữ một model Eloquent được tải trong bộ nhớ tại một thời điểm. Lấy ví dụ dưới đây.

$users = App\User::cursor()->filter(function ($user) {
    return $user->id > 500;
});

foreach ($users as $user) {
    echo $user->id;
}

Như bạn có thể thấy, trong ví dụ này, hàm gọi lại bộ lọc không được thực thi cho đến khi chúng ta thực sự lặp qua từng người dùng riêng lẻ, cho phép giảm đáng kể mức sử dụng bộ nhớ.

Bình luận (0)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday