أنماط التصميم في PHP: ليست مجرد كلمات رنانة، بل أدواتك لكتابة كود نظيف
\n\nكل مطور PHP يواجه عاجلاً أم آجلاً موقفاً يتحول فيه الكود إلى "معكرونة": تتضخم الكلاسات، وتتشابك التبعيات، وإضافة ميزة جديدة تتطلب إعادة كتابة نصف المشروع. هل يبدو ذلك مألوفاً؟
\nهنا تأتي أنماط التصميم في PHP (design patterns) لإنقاذك — وهي حلول معمارية مجربة عبر الزمن للمشاكل النمطية. ليست مكتبات جاهزة أو أجزاء كود يمكن نسخها، بل مفاهيم تساعدك في تنظيم هيكل تطبيقك ليكون مرناً، قابلاً للاختبار، وسهل الصيانة.
\nفي هذا المقال، لن نناقش النظرية من أجل النظرية. سنستعرض أمثلة كود PHP حقيقية ونجيب على السؤال الرئيسي: "متى يكون هذا النمط ضرورياً حقاً، ومتى سيعقد حياتك فقط؟".
\n\nلماذا يجب استخدام أنماط التصميم في PHP؟
\nيعتقد العديد من المطورين المبتدئين أن الأنماط هي تجريد غير ضروري. لكنها في الواقع تحل ثلاث مشاكل رئيسية:
\n- \n
- تقليل الاقتران (loose coupling) — تصبح الكلاسات أقل اعتماداً على بعضها البعض، مما يسهل استبدالها واختبارها. \n
- زيادة إعادة الاستخدام — لن تضطر لكتابة نفس الكود في أماكن مختلفة. \n
- تبسيط إعادة الهيكلة — عندما تتغير المتطلبات (وهي تتغير دائماً)، يسمح لك النمط بإجراء تغييرات محلية دون كسر النظام بأكمله. \n
لكن هناك نقطة مهمة: يجب تطبيق الأنماط بوعي. إذا كان لديك تطبيق CRUD بسيط بثلاثة جداول، فإن إضافة Factory معقدة أو Builder مجردة هو هندسة مفرطة. النمط يكون مبرراً عندما تتوقع زيادة التعقيد أو عندما تبدأ البنية الحالية في "المعاناة".
\n\nأفضل 5 أنماط تصميم في PHP مع أمثلة
\n\n1. Singleton (المفرد) — عندما يجب أن يكون الكائن واحداً
\nمتى تستخدمه: تحتاج إلى نسخة واحدة فقط من كلاس للتطبيق بأكمله. المثال الكلاسيكي هو الاتصال بقاعدة البيانات أو مسجل الأحداث (logger). إذا أنشأت اتصالاً جديداً في كل Controller، فقد تستنفد حد الاتصالات المسموح به.
\nclass Database {\n private static ?Database $instance = null;\n private PDO $connection;\n\n private function __construct() {\n $this->connection = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');\n }\n\n // منع الاستنساخ وإلغاء التسلسل\n private function __clone() {}\n public function __wakeup() {\n throw new \\Exception("Cannot unserialize singleton");\n }\n\n public static function getInstance(): Database {\n if (self::$instance === null) {\n self::$instance = new self();\n }\n return self::$instance;\n }\n\n public function getConnection(): PDO {\n return $this->connection;\n }\n}\n\n// الاستخدام\n$db = Database::getInstance();\n$pdo = $db->getConnection();\nهام: غالباً ما يُنتقد Singleton لأنه يخلق حالة عامة (global state). في الأطر الحديثة (Laravel, Symfony) يتم استبداله بحاوية Dependency Injection. استخدم Singleton فقط في المشاريع البسيطة التي لا تحتوي على DI.
\n\n2. Factory Method (طريقة المصنع) — عندما يكون إنشاء الكائن معقداً
\nمتى تستخدمه: لا تعرف مسبقاً أي كلاس محدد تحتاج إلى إنشائه، أو أن عملية تهيئة الكائن تتطلب عدة خطوات. مثال: إنشاء أنواع مختلفة من الإشعارات (Email, SMS, Push).
\ninterface Notification {\n public function send(string $message): void;\n}\n\nclass EmailNotification implements Notification {\n public function send(string $message): void {\n echo "إرسال Email: $message\\n";\n }\n}\n\nclass SMSNotification implements Notification {\n public function send(string $mess