مقدمة: لماذا SOLID ليس مجرد عقيدة، بل أداة
\nمعظم المطورين يعرفون أن SOLID هي خمسة مبادئ للبرمجة كائنية التوجه: Single Responsibility، Open-Closed، Liskov Substitution، Interface Segregation و Dependency Inversion. لكن عمليًا، غالبًا ما يقتصر الفهم على اتباع القواعد بشكل آلي. في هذه المقالة سنذهب أبعد من ذلك: سنستعرض سيناريوهات متقدمة لتطبيق SOLID في PHP، ونناقش الأنماط المضادة التي تخالف المبادئ، ونوضح كيف أن إعادة الهيكلة وفقًا لـ SOLID تجعل الكود مرنًا وقابلًا للاختبار.
\nالمادة موجهة للمطورين من مستوى Middle+ و Senior الذين يكتبون بالفعل بلغة PHP ويرغبون في تحسين بنية مشاريعهم.
\n\n1. مبدأ المسؤولية الواحدة (SRP): عندما "يعرف الفصل أكثر من اللازم"
\nالصيغة الكلاسيكية: "يجب أن يكون للفصل سبب واحد فقط للتغيير". على المستوى المتقدم، من المهم فهم أن "سبب التغيير" هو متطلب عمل. إذا تغير فصلك بسبب تغيير قواعد التحقق، أو تنسيق الإخراج، أو منطق الحفظ - فهذا انتهاك لـ SRP.
\n\nمثال على الانتهاك (God Object)
\nclass OrderProcessor {\n public function process(array $data): void {\n // 1. التحقق من البيانات\n if (empty($data['user_id']) || empty($data['items'])) {\n throw new InvalidArgumentException('Invalid order data');\n }\n \n // 2. حساب التكلفة\n $total = 0;\n foreach ($data['items'] as $item) {\n $total += $item['price'] * $item['quantity'];\n }\n \n // 3. الحفظ في قاعدة البيانات\n $sql = "INSERT INTO orders (user_id, total, status) VALUES (?, ?, 'pending')";\n // ... تنفيذ الاستعلام\n \n // 4. إرسال البريد الإلكتروني\n mail($data['user_email'], 'Order confirmation', "Total: $total");\n }\n}\n\nإعادة الهيكلة مع SRP
\nنقسم إلى ثلاثة فصول بمناطق مسؤولية واضحة:
\nclass OrderValidator {\n public function validate(array $data): void {\n if (empty($data['user_id']) || empty($data['items'])) {\n throw new InvalidArgumentException('Invalid order data');\n }\n }\n}\n\nclass OrderCalculator {\n public function calculateTotal(array $items): float {\n return array_reduce($items, function ($carry, $item) {\n return $carry + $item['price'] * $item['quantity'];\n }, 0.0);\n }\n}\n\nclass OrderRepository {\n public function save(int $userId, float $total, string $status = 'pending'): int {\n // منطق الحفظ في قاعدة البيانات\n return 42; // معرف الطلب\n }\n}\n\nclass OrderProcessor {\n public function __construct(\n private OrderValidator $validator,\n private OrderCalculator $calculator,\n private OrderRepository $repository,\n private Mailer $mailer\n ) {}\n \n public function process(array $data): void {\n $this->validator->validate($data);\n $total = $this->calculator->calculateTotal($data['items']);\n $orderId = $this->repository->save($data['user_id'], $total);\n $this->mailer->send($data['user_email'], 'Order #' . $orderId);\n }\n}\n\n2. مبدأ الانفتاح/الإغلاق (OCP): التوسع دون تعديل
\nجوهر OCP: يجب أن تكون الفصول مفتوحة للتوسع، ولكن مغلقة للتعديل. عمليًا، هذا يعني استخدام تعدد الأشكال والتجريدات بدلاً من الهياكل الشرطية.
\n\nانتهاك OCP: switch-case لكل نوع جديد
\nclass PaymentProcessor {\n public function pay(string $type, float $amount): void {\n switch ($type) {\n case 'credit_card':\n // معالجة البطاقة\n break;\n case 'paypal':\n // معالجة PayPal\n break;\n // عند إضافة نوع جديد - نعدل الفصل!\n }\n }\n}