תבנית 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");
}
אתגר
קלבואו נבנה מנהל תצורה באמצעות דפוס 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 שאוחזר דרך ההפניה השנייה
?>השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים (OOP)
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםמילת המפתח $thisמתודותמאפייניםבנאי (__construct)הורס (__destruct)חזרה: מחשבון פשוט4ירושה
ירושה בסיסיתמילת המפתח parent::דריסת מתודותמילת המפתח finalמחלקות מופשטותסיכום – היררכיית עובדים7כימוס
ציבורי, מוגן, פרטימפרטי גישה לעומקמתודות גישה ועדכוןהסתרת מידעקידום פרמטרים בבנאי (8.0)סיכום – מערכת רישומי תלמידים2מרחבי שמות וטעינה אוטומטית
מבוא למרחבי שמותמילת המפתח useתקן הטעינה האוטומטית PSR-4הטוען האוטומטי של Composerסיכום – פרויקט מאורגן5ממשקים וחוזים
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםממשק לעומת מחלקה מופשטתרמזי טיפוסים עם ממשקיםסיכום - מחשבון צורות8מתודות קסם
מבוא למתודות קסם__toString ו־__debugInfo__get, __set, __isset, __unset__call ו־__callStatic__clone ושיבוט אובייקטים__serialize ו־__unserializeסיכום – אוסף מותאם אישית3מאפייני מחלקה
מאפייני מופע לעומת מאפיינים סטטייםקבועים במחלקותמתודות ומאפיינים סטטייםמאפיינים פרטיים ומוגניםמאפיינים לקריאה בלבד (PHP 8.1)סיכום – מנהל חשבון בנק6פולימורפיזם
בחינה מחדש של דריסת מתודותפולימורפיזם באמצעות ממשקיםרמזי טיפוסים וטיפוסי איחודקישור סטטי מאוחרסיכום — מעבד תשלומיםתרגלו בעצמכם: קומפיילר PHP אונליין