Menu
CoddyTech

Bộ sinh và bộ lặp

Thuộc phần Lập trình hướng đối tượng trong hành trình PHP của Coddy. Bài học 62 trên 91.

Bộ tạo cung cấp cách đơn giản để tạo trình lặp mà không cần triển khai đầy đủ giao diện Iterator. Hàm tạo dùng yield thay cho return để tạo từng giá trị một, tạm dừng quá trình thực thi giữa các giá trị.

Đây là một bộ tạo cơ bản tạo ra một dãy số:

<?php
function countTo(int $max): Generator {
    for ($i = 1; $i <= $max; $i++) {
        yield $i;
    }
}

foreach (countTo(3) as $number) {
    echo "$number\n";
}

Đầu ra:

1
2
3

Ưu điểm chính là tiết kiệm bộ nhớ. Thay vì tạo cả một mảng trong bộ nhớ, generator tạo giá trị khi cần. Điều này rất quan trọng khi xử lý tập dữ liệu lớn. Một generator xử lý một triệu bản ghi dùng lượng bộ nhớ bằng với generator xử lý mười bản ghi.

Generator cũng có thể tạo ra các cặp khóa-giá trị:

<?php
function userGenerator(): Generator {
    yield 'admin' => 'Alice';
    yield 'editor' => 'Bob';
}

foreach (userGenerator() as $role => $name) {
    echo "$role: $name\n";
}

Đầu ra:

admin: Alice
editor: Bob

Để các lớp (class) của riêng bạn có thể lặp qua bằng foreach, hãy triển khai giao diện Iterator. Tuy nhiên, trong hầu hết trường hợp, bộ tạo (generator) là giải pháp gọn gàng hơn, với ít code khuôn mẫu hơn. Bộ tạo đặc biệt hữu ích trong lập trình hướng đối tượng (OOP) khi một lớp cần cung cấp một tập hợp các mục mà không tải tất cả vào bộ nhớ cùng lúc.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống quản lý kho sản phẩm sử dụng generator để lặp qua các bộ sưu tập lớn một cách hiệu quả mà không cần tải tất cả vào bộ nhớ cùng lúc. Bạn sẽ tạo một lớp lưu trữ sản phẩm và cung cấp các phương thức generator để lặp qua chúng theo nhiều cách khác nhau.

Bạn sẽ sắp xếp code trong ba tệp:

  • Product.php: Tạo lớp Product đại diện cho một mặt hàng trong kho. Dùng cách khai báo thuộc tính trong hàm khởi tạo để định nghĩa $sku công khai (chuỗi), $name công khai (chuỗi) và $price công khai (số thực).
  • Inventory.php: Tạo lớp Inventory quản lý một bộ sưu tập sản phẩm và cung cấp các phương thức generator để lặp qua chúng. Thêm tệp Product vào. Lớp cần:
    • Có một thuộc tính mảng riêng tư để lưu trữ sản phẩm
    • Có phương thức addProduct(Product $product) để thêm sản phẩm vào bộ sưu tập
    • Có phương thức generator allProducts(): Generator để lần lượt trả về từng sản phẩm
    • Có phương thức generator expensiveProducts(float $minPrice): Generator để chỉ trả về những sản phẩm có giá lớn hơn hoặc bằng mức tối thiểu đã cho, dưới dạng các cặp khóa-giá trị, trong đó khóa là SKU và giá trị là sản phẩm
  • main.php: Thêm tệp Inventory vào. Bạn sẽ nhận một đầu vào: ngưỡng giá tối thiểu.

    Tạo một đối tượng Inventory và thêm ba sản phẩm sau:

    • SKU: "A001", Tên: "Laptop", Giá: 999.99
    • SKU: "A002", Tên: "Mouse", Giá: 29.99
    • SKU: "A003", Tên: "Monitor", Giá: 349.99

    Trước tiên, lặp qua allProducts() và in tên của từng sản phẩm trên một dòng riêng.

    Sau đó in một dòng trống, rồi lặp qua expensiveProducts() với ngưỡng đầu vào. Với mỗi sản phẩm giá cao, in "[sku]: [name] - $[price]" trên một dòng riêng. Định dạng giá với chính xác 2 chữ số thập phân.

Thử thách này minh họa cách generator cho phép bạn lặp qua các bộ sưu tập theo kiểu tải lười: mỗi sản phẩm chỉ được trả về khi có yêu cầu, giúp cách tiếp cận này tiết kiệm bộ nhớ với kho hàng lớn. Việc trả về các cặp khóa-giá trị trong expensiveProducts() cho thấy generator có thể cung cấp dữ liệu lặp có cấu trúc.

Tự làm thử

<?php

require_once 'Inventory.php';

// Đọc đầu vào
$minPrice = floatval(trim(fgets(STDIN)));

// TODO: Tạo một instance của Inventory

// TODO: Thêm ba sản phẩm:
// SKU: "A001", Tên: "Laptop", Giá: 999.99
// SKU: "A002", Tên: "Mouse", Giá: 29.99
// SKU: "A003", Tên: "Monitor", Giá: 349.99

// TODO: Duyệt qua allProducts() và in ra tên của từng sản phẩm

// TODO: In ra một dòng trống

// TODO: Duyệt qua expensiveProducts() bằng $minPrice
// Với mỗi sản phẩm đắt tiền, in ra "[sku]: [name] - $[price]"
// Định dạng giá với đúng 2 chữ số thập phân

?>
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Lập trình hướng đối tượng

Tự luyện tập: Trình biên dịch PHP online