Menu
Coddy logo textTech

הזרקת תלויות

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

בשיעור הקודם ראית איך קומפוזיציה מאפשרת ל־Car להכיל אובייקט Engine. אבל יש בעיה ביצירת תלויות בתוך המחלקה — היא הופכת את הקוד לנוקשה וקשה לבדיקה. הזרקת תלויות פותרת זאת על ידי העברת תלויות מבחוץ במקום ליצור אותן בתוך המחלקה.

השוו בין שתי הגישות האלה:

<?php
// ללא DI - התלות נוצרת בפנים
class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine(); // צימוד הדוק
    }
}

// עם DI - התלות מועברת פנימה
class Car {
    public function __construct(private Engine $engine) {}
}

$engine = new Engine();
$car = new Car($engine); // מוזרק מבחוץ

הגישה השנייה היא הזרקת תלויות. ה־Car לא יוצר מנוע משלו — הוא מקבל אחד. לשינוי הפשוט הזה יש יתרונות משמעותיים: אפשר להעביר סוגים שונים של מנועים, להחליף מימושים לצורכי בדיקה, והמחלקה נעשית גמישה יותר.

לגמישות רבה עוד יותר, הזריקו ממשקים במקום מחלקות קונקרטיות:

<?php
interface EngineInterface {
    public function start(): string;
}

class Car {
    public function __construct(private EngineInterface $engine) {}
    
    public function start(): string {
        return $this->engine->start();
    }
}

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

challenge icon

אתגר

קל

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

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

  • MessageSenderInterface.php: הגדירו ממשק בשם MessageSenderInterface עם מתודה יחידה send(string $recipient, string $message): string. הממשק הזה מגדיר את החוזה שעליו כל שולח הודעות לעמוד.
  • EmailSender.php: צרו מחלקה EmailSender שמממשת את MessageSenderInterface. כללו את קובץ הממשק. המתודה send() צריכה להחזיר את "Email to [recipient]: [message]".
  • NotificationService.php: צרו מחלקה NotificationService שמקבלת את התלות שלה דרך הבנאי. כללו את קובץ הממשק. המחלקה צריכה:
    • לקבל MessageSenderInterface בבנאי באמצעות קידום מאפיינים בבנאי
    • להכיל מתודה notify(string $recipient, string $message) שמעבירה את הקריאה לשולח שהוזרק ומחזירה את התוצאה שלו
    שימו לב ש-NotificationService תלויה בממשק, ולא במחלקה קונקרטית. פירוש הדבר שאפשר להזריק כל שולח שמממש את הממשק בלי לשנות את השירות.
  • main.php: כללו את הקבצים EmailSender ו-NotificationService. תקבלו שתי קלטים: נמען והודעה. צרו EmailSender, הזריקו אותו אל NotificationService, ואז קראו ל-notify() והדפיסו את התוצאה.

התבנית הזאת שומרת על הגמישות של NotificationService. היא עובדת עם כל שולח שתזריקו לה, בין אם מדובר בדוא"ל, ב-SMS או במשהו שעדיין לא בניתם. השירות לא יוצר את התלויות של עצמו; הוא מקבל אותן מבחוץ.

נסו בעצמכם

<?php
require_once 'EmailSender.php';
require_once 'NotificationService.php';

// קרא את הקלט
$recipient = trim(fgets(STDIN));
$message = trim(fgets(STDIN));

// TODO: צור מופע של EmailSender
// TODO: הזרק אותו ל-NotificationService
// TODO: קרא ל-notify() והדפס את התוצאה

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

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

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

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