فهم الوراثة
تسمح لك الوراثة بإنشاء صنف جديد بناءً على صنف موجود. يرث الصنف الجديد (الابن) جميع الخصائص والدوال من الصنف الموجود (الأب)، ويمكنه إضافة أو تجاوز الوظائف.
المصطلحات الأساسية:
- الصنف الأب (الأساس/الفائق): الصنف الذي يتم الوراثة منه
- الصنف الابن (المشتق/الفرعي): الصنف الذي يرث
- extends: الكلمة المفتاحية المستخدمة لإنشاء الوراثة
- الوراثة تعزز إعادة استخدام الكود وتنشئ علاقات بين الأصناف
مثال وراثة أساسي
لننشئ تسلسل وراثة بسيط:
<?php
// الصنف الأب
class Animal {
protected $name;
protected $age;
protected $species;
public function __construct($name, $age, $species) {
$this->name = $name;
$this->age = $age;
$this->species = $species;
}
public function eat() {
return "{$this->name} يأكل.";
}
public function sleep() {
return "{$this->name} ينام.";
}
public function getInfo() {
return "{$this->name} هو {$this->species} عمره {$this->age} سنوات";
}
}
// الصنف الابن يرث من Animal
class Dog extends Animal {
private $breed;
public function __construct($name, $age, $breed) {
// استدعاء بناء الأب
parent::__construct($name, $age, "كلب");
$this->breed = $breed;
}
// إضافة دالة جديدة خاصة بـ Dog
public function bark() {
return "{$this->name} يقول: عواء! عواء!";
}
// إضافة دالة أخرى
public function fetch() {
return "{$this->name} يحضر الكرة!";
}
}
// صنف ابن آخر
class Cat extends Animal {
private $color;
public function __construct($name, $age, $color) {
parent::__construct($name, $age, "قطة");
$this->color = $color;
}
public function meow() {
return "{$this->name} يقول: مواء!";
}
public function scratch() {
return "{$this->name} يخدش الأثاث!";
}
}
// الاستخدام
$dog = new Dog("ماكس", 3, "لابرادور");
echo $dog->bark(); // دالة خاصة بالكلب
echo $dog->eat(); // موروثة من Animal
echo $dog->sleep(); // موروثة من Animal
echo $dog->getInfo(); // موروثة من Animal
$cat = new Cat("ويسكرز", 2, "رمادي");
echo $cat->meow(); // دالة خاصة بالقطة
echo $cat->eat(); // موروثة من Animal
?>
parent::__construct(): استدعِ دائماً بناء الأب لتهيئة الخصائص الموروثة بشكل صحيح. استخدم parent:: للوصول إلى دوال الصنف الأب.
تجاوز الدوال
يمكن للأصناف الأبناء تجاوز دوال الأب لتوفير سلوك متخصص:
<?php
class Animal {
protected $name;
public function __construct($name) {
$this->name = $name;
}
public function makeSound() {
return "{$this->name} يصدر صوتاً";
}
public function move() {
return "{$this->name} يتحرك";
}
}
class Dog extends Animal {
// تجاوز دالة makeSound
public function makeSound() {
return "{$this->name} ينبح: عواء! عواء!";
}
// تجاوز دالة move
public function move() {
return "{$this->name} يجري على أربع أرجل";
}
}
class Bird extends Animal {
// تجاوز دالة makeSound
public function makeSound() {
return "{$this->name} يزقزق: تغريد! تغريد!";
}
// تجاوز دالة move
public function move() {
return "{$this->name} يطير في السماء";
}
}
class Fish extends Animal {
// تجاوز دالة makeSound
public function makeSound() {
return "{$this->name} يصنع فقاعات";
}
// تجاوز دالة move
public function move() {
return "{$this->name} يسبح تحت الماء";
}
}
// كل حيوان يتصرف بشكل مختلف
$dog = new Dog("ماكس");
echo $dog->makeSound(); // ماكس ينبح: عواء! عواء!
echo $dog->move(); // ماكس يجري على أربع أرجل
$bird = new Bird("تويتي");
echo $bird->makeSound(); // تويتي يزقزق: تغريد! تغريد!
echo $bird->move(); // تويتي يطير في السماء
$fish = new Fish("نيمو");
echo $fish->makeSound(); // نيمو يصنع فقاعات
echo $fish->move(); // نيمو يسبح تحت الماء
?>
فهم التعددية الشكلية
التعددية الشكلية تعني "أشكال متعددة." تسمح للكائنات من أصناف مختلفة بأن تُعامل ككائنات من صنف أب مشترك، مع الحفاظ على سلوكياتها الفريدة.
<?php
// التعددية الشكلية في العمل
function describeAnimal(Animal $animal) {
echo $animal->makeSound() . "\n";
echo $animal->move() . "\n";
}
$dog = new Dog("بادي");
$bird = new Bird("تشيربي");
$fish = new Fish("جولدي");
// نفس الدالة تتعامل مع أنواع حيوانات مختلفة
describeAnimal($dog); // سلوك الكلب
describeAnimal($bird); // سلوك الطائر
describeAnimal($fish); // سلوك السمكة
?>
فوائد التعددية الشكلية:
- مرونة الكود: كتابة دوال تعمل مع أي صنف فرعي
- قابلية التوسع: إضافة أصناف جديدة دون تغيير الكود الموجود
- قابلية الصيانة: أسهل في إدارة وتحديث الكود
مثال واقعي: نظام الموظفين
لنبني نظام إدارة موظفين عملي:
<?php
class Employee {
protected $name;
protected $id;
protected $baseSalary;
protected $department;
public function __construct($name, $id, $baseSalary, $department) {
$this->name = $name;
$this->id = $id;
$this->baseSalary = $baseSalary;
$this->department = $department;
}
public function getName() {
return $this->name;
}
public function getId() {
return $this->id;
}
// يمكن تجاوزها من قبل الأصناف الأبناء
public function calculateSalary() {
return $this->baseSalary;
}
public function getDetails() {
return "المعرف: {$this->id}, الاسم: {$this->name}, القسم: {$this->department}";
}
// يمكن تجاوزها لأنواع موظفين مختلفة
public function getRole() {
return "موظف";
}
}
class Manager extends Employee {
private $bonus;
private $teamSize;
public function __construct($name, $id, $baseSalary, $department, $teamSize) {
parent::__construct($name, $id, $baseSalary, $department);
$this->teamSize = $teamSize;
$this->bonus = 0;
}
public function setBonus($amount) {
$this->bonus = $amount;
}
// تجاوز حساب الراتب
public function calculateSalary() {
return $this->baseSalary + $this->bonus;
}
// تجاوز الدور
public function getRole() {
return "مدير (فريق من {$this->teamSize})";
}
public function conductMeeting() {
return "{$this->name} يعقد اجتماع فريق";
}
}
class Developer extends Employee {
private $programmingLanguages;
private $projectBonus;
public function __construct($name, $id, $baseSalary, $department, $languages) {
parent::__construct($name, $id, $baseSalary, $department);
$this->programmingLanguages = $languages;
$this->projectBonus = 0;
}
public function addProjectBonus($amount) {
$this->projectBonus += $amount;
}
// تجاوز حساب الراتب
public function calculateSalary() {
return $this->baseSalary + $this->projectBonus;
}
// تجاوز الدور
public function getRole() {
return "مطور (" . implode(", ", $this->programmingLanguages) . ")";
}
public function writeCode() {
return "{$this->name} يكتب كود بـ " . implode(", ", $this->programmingLanguages);
}
}
class Intern extends Employee {
private $mentor;
private $duration; // أشهر
public function __construct($name, $id, $baseSalary, $department, $mentor, $duration) {
parent::__construct($name, $id, $baseSalary, $department);
$this->mentor = $mentor;
$this->duration = $duration;
}
// تجاوز حساب الراتب (المتدربون قد يحصلون على راتب مخفض)
public function calculateSalary() {
return $this->baseSalary * 0.6; // 60% من الراتب الأساسي
}
// تجاوز الدور
public function getRole() {
return "متدرب (برنامج {$this->duration} أشهر)";
}
public function learn() {
return "{$this->name} يتعلم من المرشد: {$this->mentor}";
}
}
// دالة تستخدم التعددية الشكلية
function printEmployeeReport(Employee $employee) {
echo "=== تقرير الموظف ===\n";
echo $employee->getDetails() . "\n";
echo "الدور: " . $employee->getRole() . "\n";
echo "الراتب: $" . number_format($employee->calculateSalary(), 2) . "\n";
echo "===================\n\n";
}
// إنشاء موظفين مختلفين
$manager = new Manager("أحمد علي", "M001", 8000, "الهندسة", 10);
$manager->setBonus(2000);
$dev = new Developer("سارة حسن", "D001", 6000, "الهندسة", ["PHP", "JavaScript", "Python"]);
$dev->addProjectBonus(1000);
$intern = new Intern("عمر خليل", "I001", 2000, "الهندسة", "سارة حسن", 6);
// استخدام التعددية الشكلية - نفس الدالة لجميع أنواع الموظفين
printEmployeeReport($manager);
printEmployeeReport($dev);
printEmployeeReport($intern);
// دوال خاصة بالنوع
echo $manager->conductMeeting() . "\n";
echo $dev->writeCode() . "\n";
echo $intern->learn() . "\n";
?>
الكلمة المفتاحية final
استخدم final لمنع الأصناف من الوراثة أو الدوال من التجاوز:
<?php
// لا يمكن الوراثة منه
final class Configuration {
private $settings;
public function get($key) {
return $this->settings[$key] ?? null;
}
}
// هذا سيسبب خطأ:
// class CustomConfig extends Configuration {} // خطأ!
class User {
protected $name;
// لا يمكن تجاوزها في الأصناف الأبناء
final public function getId() {
return $this->id;
}
// يمكن تجاوزها
public function getRole() {
return "مستخدم";
}
}
class Admin extends User {
// هذا جيد
public function getRole() {
return "مسؤول";
}
// هذا سيسبب خطأ:
// public function getId() {} // خطأ: لا يمكن تجاوز دالة final
}
?>
متى تستخدم final: استخدمها للدوال الحرجة التي يجب ألا تُغير (الأمان، الترخيص، الوظائف الأساسية) أو للأصناف التي لا يجب الوراثة منها.
الأصناف المجردة
تعمل الأصناف المجردة كقوالب ولا يمكن إنشاء مثيل منها مباشرة:
<?php
abstract class Shape {
protected $color;
public function __construct($color) {
$this->color = $color;
}
public function getColor() {
return $this->color;
}
// دالة مجردة - يجب تنفيذها من قبل الأصناف الأبناء
abstract public function calculateArea();
abstract public function calculatePerimeter();
// دالة ملموسة - يمكن استخدامها كما هي
public function describe() {
return "شكل {$this->color} بمساحة " . $this->calculateArea();
}
}
class Rectangle extends Shape {
private $width;
private $height;
public function __construct($color, $width, $height) {
parent::__construct($color);
$this->width = $width;
$this->height = $height;
}
// يجب تنفيذ الدوال المجردة
public function calculateArea() {
return $this->width * $this->height;
}
public function calculatePerimeter() {
return 2 * ($this->width + $this->height);
}
}
class Circle extends Shape {
private $radius;
public function __construct($color, $radius) {
parent::__construct($color);
$this->radius = $radius;
}
public function calculateArea() {
return pi() * $this->radius ** 2;
}
public function calculatePerimeter() {
return 2 * pi() * $this->radius;
}
}
// لا يمكن فعل هذا:
// $shape = new Shape("أحمر"); // خطأ: لا يمكن إنشاء مثيل من صنف مجرد
// يمكن فعل هذا:
$rect = new Rectangle("أزرق", 10, 5);
echo $rect->describe(); // شكل أزرق بمساحة 50
echo $rect->calculatePerimeter(); // 30
$circle = new Circle("أحمر", 7);
echo $circle->describe(); // شكل أحمر بمساحة 153.94
echo $circle->calculatePerimeter(); // 43.98
?>
الأصناف المجردة مقابل الأصناف العادية:
- مجرد: لا يمكن إنشاء مثيل منه، يمكن أن يحتوي على دوال مجردة
- عادي: يمكن إنشاء مثيل منه، يجب تنفيذ جميع الدوال
- استخدم مجرد: عندما تريد تعريف واجهة مشتركة لكن إجبار الأصناف الأبناء على تنفيذ دوال محددة
الوراثة متعددة المستويات
يمكن للأصناف أن ترث من أصناف ترث من أصناف أخرى:
<?php
class Vehicle {
protected $brand;
public function __construct($brand) {
$this->brand = $brand;
}
public function start() {
return "بدء مركبة {$this->brand}...";
}
}
class Car extends Vehicle {
protected $doors;
public function __construct($brand, $doors) {
parent::__construct($brand);
$this->doors = $doors;
}
public function honk() {
return "بيب بيب!";
}
}
class ElectricCar extends Car {
private $batteryCapacity;
public function __construct($brand, $doors, $batteryCapacity) {
parent::__construct($brand, $doors);
$this->batteryCapacity = $batteryCapacity;
}
public function charge() {
return "شحن {$this->brand} ببطارية {$this->batteryCapacity}kWh";
}
// يمكن الوصول إلى دوال من جميع الأجداد
public function displayInfo() {
return $this->start() . " " . $this->honk() . " " . $this->charge();
}
}
$tesla = new ElectricCar("تسلا", 4, 100);
echo $tesla->start(); // من Vehicle
echo $tesla->honk(); // من Car
echo $tesla->charge(); // من ElectricCar
echo $tesla->displayInfo(); // يستخدم الثلاثة
?>
تمرين:
أنشئ نظام معالجة مدفوعات مع الوراثة:
- صنف مجرد
Payment مع خصائص: amount, currency, status
- دوال مجردة:
processPayment(), validatePayment()
- دالة ملموسة:
getDetails()
- صنف
CreditCardPayment يرث من Payment مع: cardNumber, expiryDate, cvv
- صنف
PayPalPayment يرث من Payment مع: email, transactionId
- صنف
BankTransferPayment يرث من Payment مع: accountNumber, bankName
- نفذ جميع الدوال المجردة بمنطق مناسب
- أنشئ دالة
processPayments(array $payments) تستخدم التعددية الشكلية
أفضل الممارسات
إرشادات مهمة:
- فضل التكوين على الوراثة: أحياناً من الأفضل أن تحتوي الكائنات على كائنات أخرى بدلاً من الوراثة
- احتفظ بالوراثة سطحية: تجنب سلاسل الوراثة العميقة (3+ مستويات)
- استخدم protected للبيانات المشتركة: اسمح للأصناف الأبناء بالوصول لما يحتاجونه
- استدعِ بناءات الأب: استدعِ دائماً parent::__construct() عند التجاوز
- وثق الوراثة: اجعل من الواضح أي دوال يجب/لا يجب تجاوزها
الملخص
في هذا الدرس، تعلمت:
- كيف تنشئ الوراثة علاقات أب-ابن بين الأصناف
- كيفية استخدام الكلمة المفتاحية
extends
- تجاوز الدوال لتخصيص السلوك
- التعددية الشكلية وفوائدها
- الكلمة المفتاحية
final لمنع الوراثة/التجاوز
- الأصناف المجردة كقوالب للأصناف الأبناء
- تسلسلات الوراثة متعددة المستويات
- أفضل الممارسات للوراثة الفعالة
بعد ذلك، سنتعلم عن الأعضاء الثابتة والثوابت للبيانات والوظائف على مستوى الصنف!