نمط Singleton
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 71 من 91.
إنّ نمط السينجلتون (Singleton Pattern) هو نمط تصميم إنشائي يضمن وجود مثيل واحد فقط للفئة (class) طوال دورة حياة تطبيقك. كما يوفر أيضاً نقطة وصول عامة لهذا المثيل.
هذا النمط مفيد عندما تحتاج إلى كائن واحد بالضبط لتنسيق الإجراءات عبر النظام، مثل اتصال قاعدة البيانات، أو مدير التكوين، أو المسجل. إن إنشاء مثيلات متعددة من هذه العناصر سيؤدي إلى إهدار الموارد أو التسبب في سلوك غير متسق.
إليك كيفية تنفيذ نمط 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يعتمد النمط على ثلاثة عناصر رئيسية: منشئ خاص (private constructor) يمنع استخدام new مباشرة، وخاصية ثابتة (static property) تحتفظ بالنسخة الوحيدة، ودالة ثابتة (static method) تقوم بإنشاء النسخة عند الاستدعاء الأول وتعيدها في الاستدعاءات اللاحقة.
لجعل نمط Singleton مضاداً للأخطاء حقاً، يجب عليك أيضاً منع الاستنساخ (cloning) وإلغاء التسلسل (unserialization):
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
التحدي
سهللنقم ببناء مدير إعدادات باستخدام نمط Singleton. في التطبيقات الحقيقية، عادةً ما ترغب في وجود مصدر واحد للحقيقة لإعدادات التكوين — حيث أن وجود كائنات تكوين متعددة قد يؤدي إلى سلوك غير متسق عبر نظامك.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
Config.php— أنشئ فئةConfigتطبق نمط Singleton. يجب أن يقوم مدير الإعدادات الخاص بك بـ:- تخزين الإعدادات في خاصية مصفوفة خاصة (private array property)
- امتلاك منشئ خاص (private constructor) يقوم بتهيئة مصفوفة الإعدادات كفارغة
- توفير تابع ثابت
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()، فإنك تحصل دائماً على نفس الكائن، مما يضمن أن جميع أجزاء تطبيقك تشترك في نفس حالة الإعدادات.
ورقة مرجعية
يضمن نمط المفردة (Singleton Pattern) أن الفئة (class) لديها مثيل واحد فقط طوال دورة حياة تطبيقك ويوفر نقطة وصول عالمية لهذا المثيل.
هذا النمط مفيد لكائنات مثل اتصالات قاعدة البيانات، أو مديري التكوين، أو المسجلات (loggers) حيث يؤدي وجود مثيلات متعددة إلى إهدار الموارد أو التسبب في سلوك غير متسق.
تنفيذ أساسي لنمط Singleton:
<?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;
}
}
$db1 = Database::getInstance();
$db2 = Database::getInstance();
echo $db1 === $db2 ? "Same instance" : "Different instances";
// المخرجات: Same instance
العناصر الأساسية:
- المنشئ الخاص (Private constructor) — يمنع استخدام
newمباشرة - الخاصية الثابتة (Static property) — تحتفظ بالمثيل الوحيد
- الدالة الثابتة (Static method) — تنشئ المثيل عند الاستدعاء الأول وتعيده في الاستدعاءات اللاحقة
منع الاستنساخ وإلغاء التسلسل (unserialization):
<?php
private function __clone() {}
public function __wakeup() {
throw new Exception("Cannot unserialize singleton");
}
جرّب بنفسك
<?php
require_once 'Config.php';
// قراءة المدخلات
$key = trim(fgets(STDIN));
$value = trim(fgets(STDIN));
// TODO: "MyApp" إلى "app_name" وضبط Config الحصول على مثيل
// TODO: مجدداً getInstance() باستخدام Config الحصول على مرجع ثانٍ لـ
// TODO: استخدم المرجع الثاني لضبط الإعداد باستخدام المفتاح والقيمة من المدخلات
// TODO: Singleton التحقق من أن نمط
// === بناءً على مقارنة "Same instance: false" أو "Same instance: true" طباعة -
// يوضح إجمالي الإعدادات "Settings count: [count]" طباعة -
// تم استرداده عبر المرجع الثاني app_name يوضح "App name: [value]" طباعة -
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)