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.
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ớpProductđạ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$skucông khai (chuỗi),$namecông khai (chuỗi) và$pricecông khai (số thực).Inventory.php: Tạo lớpInventoryquả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
Inventoryvà 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.- SKU:
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
?>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
1Nền tảng về OOP
Tệp bên ngoàiGiới thiệu về OOPLớp và đối tượngTừ khóa $thisPhương thứcThuộc tínhHàm khởi tạo (__construct)Hàm hủy (__destruct)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnTừ khóa parent::Ghi đè phương thứcTừ khóa finalLớp trừu tượngÔn tập: hệ thống phân cấp nhân viên7Đóng gói
Công khai, được bảo vệ, riêng tưTìm hiểu sâu về bộ điều chỉnh quyền truy cậpGetter và setterẨn thông tinRút gọn hàm khởi tạo (8.0)Ôn tập: hệ thống hồ sơ học sinh10Các khái niệm OOP nâng cao
Kết hợp hay kế thừaTiêm phụ thuộcLớp ẩn danhKiểu liệt kê (PHP 8.1)Fiber (PHP 8.1)Tìm hiểu sâu về sao chép đối tượngBộ sinh và bộ lặp2Không gian tên và tự động nạp
Giới thiệu về không gian tênTừ khóa useChuẩn tự động nạp PSR-4Trình tự động nạp của ComposerÔn tập: dự án có tổ chức5Giao diện và hợp đồng
Giới thiệu về giao diệnTriển khai giao diệnTriển khai nhiều giao diệnGiao diện và lớp trừu tượngGợi ý kiểu với giao diệnÔn tập: Máy tính hình học8Phương thức ma thuật
Giới thiệu về phương thức ma thuật__toString và __debugInfo__get, __set, __isset, __unset__call và __callStatic__clone và sao chép đối tượng__serialize và __unserializeÔn tập: Bộ sưu tập tùy chỉnh3Thuộc tính của lớp
Thuộc tính instance và staticHằng số trong lớpPhương thức và thuộc tính staticThuộc tính private và protectedThuộc tính chỉ đọc (PHP 8.1)Ôn tập: Trình quản lý tài khoản ngân hàng6Đa hình
Xem lại việc ghi đè phương thứcĐa hình qua giao diệnGợi ý kiểu và kiểu hợpLiên kết tĩnh muộnÔn tập: bộ xử lý thanh toánTự luyện tập: Trình biên dịch PHP online