أنماط التصميم في PHP: ما هي ولماذا نحتاجها؟
أنماط التصميم (design patterns) هي حلول مجربة للمشكلات النمطية في البرمجة كائنية التوجه. إنها ليست كودًا جاهزًا، بل تمثل قوالب يمكن تكييفها مع موقف معين. في PHP، تكون الأنماط مفيدة بشكل خاص لإنشاء تطبيقات ويب قابلة للتوسع والصيانة.
في هذه المقالة، سنشرح ثلاثة أنماط رئيسية: Singleton و Factory و Observer. لكل منها، سنقدم أمثلة حقيقية بلغة PHP ونشرح في أي الحالات يجب استخدامها.
لماذا يجب دراسة الأنماط في PHP؟
- تبسيط الكود — نهج موحد لحل المشكلات.
- إعادة الاستخدام — يمكن تكييف الأنماط بسهولة مع مشاريع مختلفة.
- سهولة الصيانة — يصبح الكود مفهومًا للمطورين الآخرين.
- قابلية الاختبار — استخدام الأنماط يبسط كتابة اختبارات الوحدة (unit-tests).
1. نمط Singleton (المفرد)
يضمن Singleton وجود مثيل واحد فقط للفئة، ويوفر نقطة وصول عالمية إليه. في PHP، يُستخدم هذا غالبًا للاتصال بقاعدة البيانات، أو تسجيل الأحداث (logging)، أو الإعدادات (configuration).
مثال: فئة للعمل مع قاعدة البيانات
<?phpclass Database { private static ?Database $instance = null; private PDO $connection;
private function __construct() { // الاتصال بقاعدة البيانات (مثال مع SQLite) $this->connection = new PDO('sqlite:example.db'); $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); }
public static function getInstance(): Database { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; }
public function getConnection(): PDO { return $this->connection; }
// منع الاستنساخ وإلغاء التسلسل private function __clone() {} public function __wakeup() { throw new \\Exception("Cannot unserialize singleton"); }}
// الاستخدام$db = Database::getInstance();$pdo = $db->getConnection();?>متى يتم استخدام Singleton؟
- عند الحاجة إلى مثيل واحد فقط من الفئة (مثل الاتصال بقاعدة البيانات).
- للوصول العالمي إلى مورد (logger، cache).
- في الحالات التي يؤدي فيها إنشاء مثيلات متعددة إلى تعارضات.
العيوب: ينتهك مبدأ المسؤولية الواحدة ويُعقّد الاختبار (يخلق حالة عالمية).
2. نمط Factory (المصنع)
يحدد Factory Method (طريقة المصنع) واجهة لإنشاء كائن، لكنه يسمح للفئات الفرعية بتغيير نوع الكائن الذي يتم إنشاؤه. هذا مفيد عندما يكون نوع الكائن غير معروف مسبقًا أو قد يتغير.
مثال: مصنع لإنشاء الإشعارات
<?php// واجهة لجميع أنواع الإشعاراتinterface Notification { public function send(string $message): void;}
// تطبيقات محددةclass EmailNotification implements Notification { public function send(string $message): void { echo "إرسال بريد إلكتروني: {$message}"; }}
class SMSNotification implements Notification { public function send(string $message): void { echo "إرسال رسالة نصية: {$message}"; }}
// المصنعclass NotificationFactory { public static function create(string $type): Notification { return match ($type) { 'email' => new EmailNotification(), 'sms' => new SMSNotification(), default => throw new \\InvalidArgumentException("نوع غير معروف: {$type}"), }; }}
// الاستخدام$notification = NotificationFactory::create('email');$notifica