Menu
Coddy logo textTech

תבנית Singleton

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

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

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

כך מממשים Singleton ב-PHP:

<?php
class Database {
    private static ?Database $instance = null;
    
    private function __construct() {
        // בנאי פרטי מונע יצירת מופע ישירות
    }
    
    public static function getInstance(): Database {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    public function query(string $sql): string {
        return "Executing: $sql";
    }
}

$db1 = Database::getInstance();
$db2 = Database::getInstance();

echo $db1 === $db2 ? "Same instance" : "Different instances";

פלט:

Same instance

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

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

<?php
private function __clone() {}
public function __wakeup() {
    throw new Exception("Cannot unserialize singleton");
}
challenge icon

אתגר

קל

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

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

  • Config.php: צרו מחלקה בשם Config שמממשת את דפוס Singleton. מנהל התצורה שלכם צריך:
    • לשמור את ההגדרות במאפיין מערך פרטי
    • להכיל בנאי פרטי שמאתחל את מערך ההגדרות כריק
    • לספק מתודה סטטית getInstance() שמחזירה את המופע היחיד
    • למנוע שכפול על ידי הגדרת __clone() כפרטית
    • להכיל מתודה set(string $key, string $value): void לשמירת הגדרה
    • להכיל מתודה get(string $key): ?string שמחזירה את הערך של מפתח, או null אם המפתח לא קיים
    • להכיל מתודה getAll(): array שמחזירה את כל ההגדרות
  • main.php: כללו את קובץ Config. תקבלו שתי קלטים: מפתח וערך.

    קבלו את מופע Config והגדירו הגדרת ברירת מחדל עם המפתח "app_name" והערך "MyApp".

    קבלו הפניה שנייה למופע Config (באמצעות getInstance() שוב) והשתמשו בה כדי להגדיר הגדרה נוספת באמצעות המפתח והערך מהקלטים.

    לבסוף, ודאו שדפוס Singleton פועל כראוי:

    • הדפיסו "Same instance: true" או "Same instance: false" בהתאם לשאלה אם שתי ההפניות מצביעות על אותו אובייקט (השתמשו ב-=== להשוואה)
    • הדפיסו "Settings count: [count]" כדי להציג את המספר הכולל של ההגדרות שנשמרו (השתמשו ב-count() על התוצאה של getAll())
    • הדפיסו "App name: [value]" כדי להציג את ההגדרה app_name שאוחזרה באמצעות ההפניה השנייה

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

נסו בעצמכם

<?php

require_once 'Config.php';

// קראו את הקלט
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));

// TODO: השיגו את המופע של Config והגדירו את "app_name" ל-"MyApp"

// TODO: השיגו הפניה שנייה ל-Config באמצעות קריאה נוספת ל-getInstance()

// TODO: השתמשו בהפניה השנייה כדי להגדיר את ההגדרה באמצעות $key ו-$value מהקלט

// TODO: ודאו ש-Singleton פועל:
// - הדפיסו "Same instance: true" או "Same instance: false" לפי תוצאת ההשוואה באמצעות ===
// - הדפיסו "Settings count: [count]" כדי להציג את מספר ההגדרות הכולל
// - הדפיסו "App name: [value]" כדי להציג את app_name שאוחזר דרך ההפניה השנייה

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

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

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

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