OOP & SOLIDشرح عام.
الأساس النظري اللي كل الـ frameworks الحديثة (ومنها Magento) مبنية عليه. هنفهم مبادئ الـ OOP الأربعة، وبعدين مبادئ SOLID الخمسة — بأمثلة كود بسيطة وتشبيهات، مع ربط كل مبدأ بـ Magento.
الـ OOP طريقة لتنظيم الكود حوالين objects بتجمع البيانات والسلوك، وبتقوم على أربع أعمدة: Encapsulation و Inheritance و Polymorphism و Abstraction. ومبادئ SOLID الخمسة بتوجّهك تكتب classes سهلة التعديل والاختبار. Magento 2 مبني على الأفكار دي، زي الـ Dependency Injection اللي بتطبّق مبدأ Dependency Inversion، والـ interfaces اللي بتفصل الطبقات عن بعض.
يعني إيه OOP؟
الفكرة الأساسية قبل المبادئ الأربعة.
الـ OOP (البرمجة الكائنية) هي أسلوب بننظّم بيه الكود حوالين "objects" — كل object بيجمع البيانات (properties) والسلوك (methods) اللي بيشتغل عليها في مكان واحد.
بدل ما يكون عندك بيانات مبعثرة ودوال منفصلة، بتجمّع كل حاجة متعلقة ببعض في class واحد. ده بيخلّي الكود منظّم، قابل لإعادة الاستخدام، وأسهل في الصيانة كل ما المشروع يكبر.
class Car { // properties (data) public string $color; public int $speed = 0; // method (behavior) public function accelerate(int $amount): void { $this->speed += $amount; } } // an object = an instance of the class $myCar = new Car(); $myCar->color = 'red'; $myCar->accelerate(50);
Encapsulation — التغليف
إخفاء التفاصيل الداخلية، وكشف اللي محتاج يتكشف بس.
الـ Encapsulation معناها إنك تخفي البيانات الداخلية للـ object، وتخلي التعامل معاها يتم بس عن طريق methods محددة. بتستخدم private وprotected عشان تمنع الوصول المباشر.
عشان تحمي البيانات من التعديل الغلط. لو خليت أي حد يعدّل الـ property مباشرة، ممكن يحط قيمة غلط. لكن لو خليته يعدّلها عن طريق method، تقدر تتحقق من القيمة الأول.
class BankAccount { // hidden — can't touch directly private float $balance = 0; public function deposit(float $amount): void { // validation protects the data if ($amount <= 0) { throw new \InvalidArgumentException(); } $this->balance += $amount; } public function getBalance(): float { return $this->balance; } } // $account->balance = -999; ❌ not allowed $account->deposit(100); // ✓ only safe way
Inheritance — الوراثة
class بياخد خصائص وسلوك class تاني ويبني عليه.
الـ Inheritance بتخلّي class (الابن/child) يورّث الـ properties والـ methods من class تاني (الأب/parent)، ويقدر يضيف عليها أو يعدّلها. بتستخدم كلمة extends.
عشان متكررش الكود (DRY - Don't Repeat Yourself). لو عندك خصائص مشتركة بين كذا class، بتحطها في parent واحد والكل بيورّثها.
class Animal { public function breathe(): string { return 'breathing...'; } } // Dog inherits everything from Animal class Dog extends Animal { // adds its own behavior public function bark(): string { return 'Woof!'; } } $dog = new Dog(); $dog->breathe(); // inherited $dog->bark(); // its own
Polymorphism — تعدد الأشكال
نفس الـ method بتتصرّف بشكل مختلف حسب الـ object.
الـ Polymorphism (تعدد الأشكال) معناها إن objects مختلفة تقدر تستجيب لـ نفس النداء بطرق مختلفة. بتنادي makeSound() على أي حيوان، وكل واحد بيرد بصوته.
عشان تكتب كود يتعامل مع أنواع مختلفة بنفس الطريقة. الكود بتاعك مش محتاج يعرف نوع الـ object بالظبط — بيعرف بس إنه يقدر يعمل makeSound().
interface Animal { public function makeSound(): string; } class Dog implements Animal { public function makeSound(): string { return 'Woof'; } } class Cat implements Animal { public function makeSound(): string { return 'Meow'; } } // same call, different behavior function printSound(Animal $a) { echo $a->makeSound(); } printSound(new Dog()); // Woof printSound(new Cat()); // Meow
Abstraction — التجريد
تعرض "إيه بيتعمل" وتخفي "إزاي بيتعمل".
الـ Abstraction معناها إنك تركّز على "إيه اللي الـ object بيعمله" وتخفي التفاصيل المعقدة لـ "إزاي بيعمله". بتحققه عن طريق interfaces وabstract classes.
عشان تبسّط التعامل مع الكود المعقّد. المستخدم بيشوف واجهة نظيفة بس، والتعقيد مخفي. وكمان بيسمح بتغيير التفاصيل الداخلية بدون ما يتأثر اللي بيستخدمها.
// the "what" — a clean contract interface PaymentInterface { public function pay(float $amount): bool; } // the "how" — hidden complexity class StripePayment implements PaymentInterface { public function pay(float $amount): bool { // complex Stripe API calls hidden here return true; } } // caller only knows "pay" exists function checkout(PaymentInterface $p) { $p->pay(100); }
يعني إيه SOLID؟
خمس مبادئ لكتابة كود OOP نظيف وقابل للصيانة.
SOLID اختصار لخمس مبادئ تصميم في الـ OOP، لما تتبعها بيبقى كودك سهل الفهم، مرن، وقابل للتوسعة من غير ما يتكسر.
- S — Single Responsibility (مسؤولية واحدة)
- O — Open/Closed (مفتوح للتوسعة، مقفول للتعديل)
- L — Liskov Substitution (قابلية الاستبدال)
- I — Interface Segregation (فصل الـ interfaces)
- D — Dependency Inversion (عكس الاعتماد)
Single Responsibility
كل class ليه سبب واحد بس للتغيير.
كل class المفروض يعمل حاجة واحدة بس، ويكون ليه سبب واحد للتغيير. لو الـ class بيعمل أكتر من مسؤولية، افصلهم.
class User { public function save() { /* DB logic */ } public function sendEmail() { /* email logic */ } public function generateReport() { /* report */ } // 3 responsibilities in one class! }
class User { /* just user data */ } class UserRepository { public function save() {} } class EmailService { public function send() {} } class ReportGenerator { public function generate() {} }
Open / Closed
مفتوح للتوسعة، مقفول للتعديل.
الكود المفروض يكون مفتوح للإضافة عليه (extension)، بس مقفول للتعديل فيه. يعني تقدر تضيف سلوك جديد من غير ما تغيّر الكود الموجود.
لأن كل ما تعدّل كود شغّال، ممكن تكسّر حاجة. الأأمن إنك تضيف كود جديد بدل ما تعدّل القديم.
interface Discount { public function apply(float $total): float; } // add new discounts WITHOUT touching old code class SummerDiscount implements Discount { public function apply(float $total): float { return $total * 0.9; } } class VipDiscount implements Discount { public function apply(float $total): float { return $total * 0.8; } }
Liskov Substitution
الـ child لازم يقدر ياخد مكان الـ parent من غير مشاكل.
لو عندك class أب، أي class ابن المفروض يقدر ياخد مكانه من غير ما يكسّر البرنامج. الابن لازم يحترم "العقد" بتاع الأب.
لو عندك class Bird فيه fly()، وعملت Penguin extends Bird — البطريق ميطيرش! فلو كود بيتوقع أي Bird يطير، البطريق هيكسّره. ده كسر للمبدأ.
class Bird { public function fly() { return 'flying'; } } class Penguin extends Bird { public function fly() { throw new \Exception("Can't fly!"); // breaks code expecting a Bird to fly } }
Interface Segregation
interfaces صغيرة مركّزة أحسن من واحد ضخم.
الـ class مالوش يتجبر إنه يطبّق methods هو مش محتاجها. الأحسن interfaces صغيرة ومركّزة بدل interface واحد ضخم فيه كل حاجة.
interface Worker { public function work(); public function eat(); public function sleep(); } // A robot must implement eat() & sleep()?! class Robot implements Worker { public function eat() { /* useless */ } public function sleep() { /* useless */ } }
interface Workable { public function work(); } interface Eatable { public function eat(); } // Robot only takes what it needs class Robot implements Workable { public function work() {} }
Dependency Inversion
اعتمد على abstractions مش على تفاصيل. أهم مبدأ في Magento.
الكود المفروض يعتمد على abstractions (interfaces)، مش على تفاصيل (concrete classes). يعني اطلب "interface" مش class معيّن.
عشان تفكّ الارتباط بين الكود. لو اعتمدت على interface، تقدر تغيّر الـ implementation في أي وقت (للتخصيص أو الـ testing) من غير ما تلمس الكود اللي بيستخدمه.
class OrderService { private $mailer; public function __construct() { // locked to a specific class $this->mailer = new GmailMailer(); } }
class OrderService { // depends on abstraction — any mailer works public function __construct( private readonly MailerInterface $mailer ) {} }
OOP & SOLID ✓
دلوقتي عندك الأساس النظري كامل: 4 أعمدة OOP و5 مبادئ SOLID، مع ربط كل واحد بـ Magento. المبادئ دي مش خاصة بـ Magento — دي أساس أي كود OOP محترم.
الخلاصة: SOLID بيفسّر ليه Magento متصمّم بالشكل ده. الـ DI جاي من D، الـ plugins من O، فصل الطبقات من S. مش صدفة — تصميم مقصود.
خلّصت الدرس؟علّمه عشان تتابع تقدّمك في الكورس.
أسئلة شائعة
ما هي أعمدة الـ OOP الأربعة؟
الـ OOP بتقوم على 4 أعمدة: Encapsulation (إخفاء البيانات وحمايتها)، Inheritance (class بيورّث من class تاني بـ extends)، Polymorphism (نفس النداء بيتصرّف مختلف حسب الـ object)، وAbstraction (تعرض "إيه بيتعمل" وتخفي "إزاي"). الأربعة مع بعض بيخلّوا الكود منظّم وقابل لإعادة الاستخدام وأسهل في الصيانة.
ما الفرق بين Abstraction و Encapsulation؟
الـ Encapsulation بتخفي البيانات الداخلية للحماية، بتستخدم private وprotected وتخلّي التعديل يتم عن طريق methods بتتحقق من القيمة. الـ Abstraction بتخفي التعقيد والتنفيذ للتبسيط، وبتتحقق عن طريق interfaces وabstract classes. الاتنين مترابطين بس هدفهم مختلف.
يعني إيه SOLID في البرمجة؟
SOLID اختصار لخمس مبادئ تصميم في الـ OOP: Single Responsibility، وOpen/Closed، وLiskov Substitution، وInterface Segregation، وDependency Inversion. لما تتبعهم بيبقى كودك سهل الفهم، مرن، وتقدر توسّعه من غير ما يتكسر.
إيه مثال على كسر مبدأ Liskov Substitution؟
المثال الكلاسيكي: class Bird فيه fly()، وتعمل Penguin extends Bird وترمي exception جوّه fly()، فأي كود متوقع إن أي Bird بيطير هيتكسر. الحل إنك تصمّم الـ hierarchy صح وتعمل FlyingBird وFlightlessBird منفصلين بدل ما تجبر البطريق يورّث سلوك مش بتاعه.
إزاي أطبّق Dependency Inversion في PHP؟
بدل ما تعمل new GmailMailer() جوّه الكلاس وتتربط بيه، اطلب interface في الـ constructor زي private readonly MailerInterface $mailer. كده تقدر تغيّر الـ implementation في أي وقت للتخصيص أو الـ testing من غير ما تلمس الكود اللي بيستخدمه.
إمتى أستخدم Interface Segregation؟
لما تلاقي interface ضخم بيجبر classes تطبّق methods مش محتاجاها، زي Robot مجبور يطبّق eat() وsleep() من interface اسمه Worker. قسّمه لـ interfaces صغيرة مركّزة زي Workable وEatable، وكل class ياخد اللي محتاجه بس.
إيه علاقة مبادئ SOLID بتصميم Magento 2؟
Magento متصمّم على SOLID بشكل مقصود: الـ Dependency Injection والـ di.xml جايين من Dependency Inversion، والـ plugins والـ events تطبيق لـ Open/Closed، وفصل الـ Model عن الـ ResourceModel عن الـ Block تطبيق لـ Single Responsibility. وأي preference لازم يحترم الـ interface اللي بيستبدله بالكامل عشان Liskov.