مبادئ SOLID في PHP: النظرية والتطبيق
SOLID هو اختصار لخمسة مبادئ أساسية في البرمجة كائنية التوجه، صاغها روبرت مارتن (العم بوب). تساعد هذه المبادئ في إنشاء كود مرن وقابل للصيانة والتوسع. في هذه المقالة، سنشرح كل مبدأ بأمثلة من PHP ونوضح كيفية تطبيقها في المشاريع الحقيقية.
1. Single Responsibility Principle (SRP) — مبدأ المسؤولية الواحدة
الجوهر: يجب أن يكون لكل class سبب واحد فقط للتغيير. بمعنى آخر، يجب أن يكون class مسؤولاً عن مهمة واحدة فقط.
انتهاك SRP:
class Order { public function calculateTotal() { /* ... */ } public function saveToDatabase() { /* ... */ } public function sendEmailNotification() { /* ... */ }}هنا، class Order مسؤول عن الحساب والحفظ وإرسال الإشعارات. هذا ينتهك SRP.
الحل:
class Order { public function calculateTotal() { /* ... */ }}
class OrderRepository { public function save(Order $order) { /* ... */ }}
class EmailNotificationService { public function sendOrderConfirmation(Order $order) { /* ... */ }}الآن، كل class لديه مسؤولية واحدة واضحة، مما يبسط الاختبار والتعديل.
2. Open-Closed Principle (OCP) — مبدأ الانفتاح/الإغلاق
الجوهر: يجب أن تكون class مفتوحة للتمديد ولكن مغلقة للتعديل. يجب أن تكون قادراً على إضافة وظائف جديدة دون تغيير الكود الموجود.
انتهاك OCP:
class PaymentProcessor { public function process($type) { if ($type == 'credit_card') { // معالجة بطاقة الائتمان } elseif ($type == 'paypal') { // معالجة PayPal } }}لإضافة طريقة دفع جديدة، سيتعين تعديل class PaymentProcessor.
الحل باستخدام interfaces:
interface PaymentMethod { public function process();}
class CreditCardPayment implements PaymentMethod { public function process() { /* ... */ }}
class PayPalPayment implements PaymentMethod { public function process() { /* ... */ }}
class PaymentProcessor { public function process(PaymentMethod $method) { $method->process(); }}الآن، لإضافة طريقة دفع جديدة، يكفي إنشاء class جديد يطبق interface PaymentMethod، دون تغيير الكود الموجود.
3. Liskov Substitution Principle (LSP) — مبدأ الاستبدال لباربرا ليسكوف
الجوهر: يجب أن تكون كائنات الـ subclasses قابلة للاستبدال بكائنات الـ base class دون الإخلال بصحة البرنامج. يجب ألا يغير الـ subclass السلوك المتوقع من الـ base class.
انتهاك LSP:
class Rectangle { protected $width; protected $height;
public function setWidth($w) { $this->width = $w; } public function setHeight($h) { $this->height = $h; } public function getArea() { return $this->width * $this->height; }}
class Square extends Rectangle { public function setWidth($w) { $this->width = $w; $this->height = $w; // انتهاك المبدأ } public function setHeight($h) { $this->height = $h; $this->width = $h; // انتهاك المبدأ }}إذا كان كود العميل يتوقع أن تغيير العرض لن يؤثر على الارتفاع، فإن Square سينتهك هذا التوقع.
الحل: تجنب الوراثة إذا كان الـ subclass لا يتوافق تماماً مع سلوك الـ parent. من الأفضل استخدام التركيب (composition) أو class منفصلة:
interface Shape