제너레이터와 이터레이터
Coddy PHP 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 91개 중 62번째.
생성기는 전체 Iterator 인터페이스를 구현하지 않고도 반복자를 생성할 수 있는 간단한 방법을 제공합니다. 생성기 함수는 값을 한 번에 하나씩 생성하기 위해 return 대신 yield를 사용하며, 각 값 사이에서 실행을 일시 중지합니다.
다음은 숫자 시퀀스를 생성하는 기본적인 generator입니다:
<?php
function countTo(int $max): Generator {
for ($i = 1; $i <= $max; $i++) {
yield $i;
}
}
foreach (countTo(3) as $number) {
echo "$number\n";
}
출력:
1
2
3주요 장점은 메모리 효율성입니다. 메모리에서 전체 array를 만드는 대신, generator는 필요할 때 값을 생성합니다. 이는 대규모 데이터셋을 다룰 때 매우 중요합니다. 백만 개의 레코드를 처리하는 generator도 열 개를 처리하는 generator와 동일한 메모리를 사용합니다.
Generator는 키-값 쌍도 yield할 수 있습니다:
<?php
function userGenerator(): Generator {
yield 'admin' => 'Alice';
yield 'editor' => 'Bob';
}
foreach (userGenerator() as $role => $name) {
echo "$role: $name\n";
}
출력:
admin: Alice
editor: Bobforeach를 사용하여 자신만의 클래스를 반복 가능하게 만들려면 Iterator 인터페이스를 구현하세요. 하지만 대부분의 경우 생성기는 더 적은 보일러플레이트 코드로 더 깔끔한 해결책을 제공합니다. 생성기는 특히 클래스가 모든 항목을 한 번에 메모리에 로드하지 않고 항목 컬렉션을 노출해야 하는 OOP에서 유용합니다.
챌린지
쉬움모든 항목을 한 번에 메모리에 로드하지 않고 대규모 컬렉션을 효율적으로 순회하기 위해 generator를 사용하는 product inventory system을 만들어 보겠습니다. product를 저장하고 여러 방식으로 순회할 수 있는 generator method를 제공하는 class를 만들게 됩니다.
코드를 세 개의 파일로 구성합니다:
Product.php: inventory의 항목을 나타내는Productclass를 Create합니다. constructor promotion을 사용하여 public$sku(string), public$name(string), public$price(float)를 define합니다.Inventory.php: product collection을 관리하고 이를 순회할 generator method를 제공하는Inventoryclass를 Create합니다. Product file을 포함합니다. class는 다음을 수행해야 합니다:- product를 저장할 private array property를 가집니다
- product를 collection에 추가하는
addProduct(Product $product)method를 가집니다 - 각 product를 한 번에 하나씩 yield하는 generator method
allProducts(): Generator를 가집니다 - 주어진 minimum보다 price가 크거나 같은 product만 yield하는 generator method
expensiveProducts(float $minPrice): Generator를 가집니다. key-value pair를 yield하며, key는 SKU이고 value는 product입니다
main.php: Inventory file을 포함합니다. 하나의 input, 즉 minimum price threshold를 받습니다.Inventory를 Create하고 다음 세 product를 추가합니다:- SKU:
"A001", Name:"Laptop", Price:999.99 - SKU:
"A002", Name:"Mouse", Price:29.99 - SKU:
"A003", Name:"Monitor", Price:349.99
먼저
allProducts()를 통해 Iterate하고 각 product의 name을 한 줄에 하나씩 print합니다.그런 다음 empty line을 print하고, input threshold를 사용하여
expensiveProducts()를 Iterate합니다. 각 expensive product에 대해"[sku]: [name] - $[price]"를 한 줄에 하나씩 print합니다. price는 정확히 소수점 이하 2자리로 Format합니다.- SKU:
이 challenge는 generator를 사용하면 collection을 lazy하게 Iterate할 수 있음을 보여 줍니다. 각 product는 요청될 때만 yield되므로 대규모 inventory에서 이 접근 방식은 메모리 효율적입니다. expensiveProducts()에서 key-value를 yield하는 방식은 generator가 구조화된 순회 데이터를 제공하는 방법을 보여 줍니다.
직접 해보기
<?php
require_once 'Inventory.php';
// 입력 읽기
$minPrice = floatval(trim(fgets(STDIN)));
// TODO: Inventory 인스턴스 생성
// TODO: 제품 세 개 추가:
// SKU: "A001", 이름: "Laptop", 가격: 999.99
// SKU: "A002", 이름: "Mouse", 가격: 29.99
// SKU: "A003", 이름: "Monitor", 가격: 349.99
// TODO: allProducts()를 순회하며 각 제품의 이름을 출력
// TODO: 빈 줄 출력
// TODO: $minPrice를 사용하여 expensiveProducts()를 순회
// 각 고가 제품에 대해 "[sku]: [name] - $[price]"를 출력
// 가격을 정확히 소수점 2자리로 포맷
?>이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 PHP 컴파일러