Menu
Coddy logo textTech

מחוללים ואיטרטורים

חלק מהיחידה תכנות מונחה עצמים במסלול ה-PHP של Coddy. שיעור 62 מתוך 91.

מחוללים מספקים דרך פשוטה ליצור איטרטורים בלי לממש את הממשק המלא Iterator. פונקציית מחולל משתמשת ב-yield במקום ב-return כדי להפיק ערכים בזה אחר זה, תוך השהיית הביצוע בין ערך לערך.

הנה מחולל בסיסי שמפיק רצף של מספרים:

<?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

היתרון המרכזי הוא יעילות בזיכרון. במקום ליצור מערך שלם בזיכרון, מחוללים מפיקים ערכים לפי דרישה. זה חיוני כשעובדים עם מערכי נתונים גדולים — מחולל שמעבד מיליון רשומות משתמש באותה כמות זיכרון כמו מחולל שמעבד עשר.

מחוללים יכולים גם להניב זוגות של מפתח וערך:

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

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

פלט:

admin: Alice
editor: Bob

כדי להפוך את המחלקות שלך לניתנות לאיטרציה באמצעות foreach, ממשו את הממשק Iterator. עם זאת, ברוב המקרים מחוללים מציעים פתרון נקי יותר עם פחות קוד תשתיתי. הם שימושיים במיוחד בתכנות מונחה עצמים, כאשר מחלקה צריכה לחשוף אוסף של פריטים בלי לטעון הכול לזיכרון בבת אחת.

challenge icon

אתגר

קל

בואו נבנה מערכת לניהול מלאי מוצרים שמשתמשת במחוללים כדי לעבור ביעילות על אוספים גדולים בלי לטעון את הכול לזיכרון בבת אחת. תיצרו מחלקה ששומרת מוצרים ומספקת מתודות מחולל למעבר עליהם בדרכים שונות.

תארגנו את הקוד בשלושה קבצים:

  • Product.php: צרו מחלקה Product שמייצגת פריט במלאי. השתמשו בקידום מאפיינים בבנאי כדי להגדיר $sku ציבורי מסוג מחרוזת, $name ציבורי מסוג מחרוזת ו-$price ציבורי מסוג מספר ממשי.
  • Inventory.php: צרו מחלקה Inventory שמנהלת אוסף מוצרים ומספקת מתודות מחולל למעבר עליהם. כללו את קובץ Product. המחלקה צריכה:
    • להכיל מאפיין מערך פרטי לאחסון המוצרים
    • להכיל מתודה addProduct(Product $product) שמוסיפה מוצר לאוסף
    • להכיל מתודת מחולל allProducts(): Generator שמחזירה כל מוצר באמצעות yield, אחד בכל פעם
    • להכיל מתודת מחולל expensiveProducts(float $minPrice): Generator שמחזירה באמצעות yield רק מוצרים שמחירם גדול מהמחיר המינימלי הנתון או שווה לו, כצמדי מפתח-ערך שבהם המפתח הוא ה-SKU והערך הוא המוצר
  • main.php: כללו את קובץ Inventory. תקבלו קלט אחד: סף מחיר מינימלי.

    צרו Inventory והוסיפו את שלושת המוצרים הבאים:

    • SKU: "A001", שם: "Laptop", מחיר: 999.99
    • SKU: "A002", שם: "Mouse", מחיר: 29.99
    • SKU: "A003", שם: "Monitor", מחיר: 349.99

    תחילה, עברו על allProducts() והדפיסו את שם המוצר של כל מוצר בשורה נפרדת.

    לאחר מכן, הדפיסו שורה ריקה, ואז עברו על expensiveProducts() באמצעות סף הקלט. עבור כל מוצר יקר, הדפיסו "[sku]: [name] - $[price]" בשורה נפרדת. עצבו את המחיר בדיוק עם 2 ספרות אחרי הנקודה העשרונית.

האתגר הזה מדגים כיצד מחוללים מאפשרים מעבר עצל על אוספים: כל מוצר מוחזר באמצעות yield רק כשהוא נדרש, וכך הגישה הזו חוסכת בזיכרון במלאי גדול. החזרת צמדי מפתח-ערך ב-expensiveProducts() מדגימה כיצד מחוללים יכולים לספק נתוני מעבר מובנים.

נסו בעצמכם

<?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: עבור על expensiveProducts() באמצעות $minPrice
// עבור כל מוצר יקר, הדפס "[sku]: [name] - $[price]"
// עצב את המחיר עם בדיוק 2 ספרות אחרי הנקודה העשרונית

?>
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר PHP אונליין