السمات مقابل الوراثة
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 55 من 91.
الآن بعد أن فهمت كيفية عمل السمات (traits)، دعنا نوضح متى نستخدم السمات مقابل الوراثة (inheritance). كلاهما يسمح بإعادة استخدام الكود، ولكنهما يخدمان أغراضاً مختلفة ولهما خصائص متميزة.
تُنشئ الوراثة علاقة "is-a". فئة Dog التي ترث من Animal تعني أن الكلب هو حيوان. ترث الفئة الابنة هوية الفئة الأب ويمكن استخدامها في أي مكان يُتوقع فيه النوع الأب.
توفر السمات (Traits) قدرة "يملك" (has-a). فعندما تستخدم فئة (class) سمة Loggable، فإنها تمتلك وظيفة التسجيل (logging) - لكنها لا تصبح مسجلاً (logger). تضيف السمات (Traits) سلوكاً دون تغيير ماهية الفئة بشكل أساسي.
<?php
// الوراثة: الكلب هو حيوان (Inheritance: Dog IS an Animal)
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// السمة (Trait): الكلب لديه قدرة التسجيل (Trait: Dog HAS logging capability)
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
الاختلافات الرئيسية التي يجب تذكرها:
| الجانب | الوراثة (Inheritance) | السمات (Traits) |
|---|---|---|
| العلاقة | is-a | امتلاك قدرة (has-a) |
| الحد | أب واحد فقط | يُسمح بسمات متعددة |
| التحقق من النوع | يعمل مع instanceof | لا توجد هوية نوع |
| الأفضل لـ | العلاقات الهرمية | السلوكيات المشتركة عبر فئات غير مرتبطة |
استخدم inheritance عندما تشترك classes في هوية مشتركة. استخدم traits عندما تحتاج classes غير المرتبطة إلى نفس الوظيفة دون أن تكون جزءاً من نفس شجرة العائلة.
التحدي
سهللنقم ببناء نظام مركبات يوضح متى يجب استخدام الوراثة (inheritance) مقابل السمات (traits). ستقوم بإنشاء تسلسل هرمي للمركبات التي تشترك في هوية عامة من خلال الوراثة، مع إضافة قدرات عرضية من خلال السمات.
ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:
Trackable.php— أنشئ سمة (trait) تسمىTrackableتوفر إمكانية تتبع GPS. يجب أن تحتوي السمة على:- خاصية خاصة
$location(سلسلة نصية) - دالة
setLocation(string $location)تقوم بتخزين الموقع الحالي - دالة
getLocation()تعيد"Location: [location]"
- خاصية خاصة
Vehicle.php— أنشئ فئة أساسيةVehicleتؤسس علاقة "هو" (is-a). قم بتضمين ملف السمة. استخدم ترقية المنشئ (constructor promotion) لتعريف خاصية محمية$brand. أضف دالةdescribe()تعيد"Vehicle: [brand]". يجب أن تستخدم هذه الفئة سمةTrackableلأن جميع المركبات في أسطولنا ستحتوي على GPS.Car.php— أنشئ فئةCarترث منVehicle. قم بتضمين ملف Vehicle. استخدم ترقية المنشئ لقبول العلامة التجارية وخاصية خاصة$doors(عدد صحيح). استدعِ منشئ الفئة الأب بالعلامة التجارية. قم بإعادة كتابة (Override) دالةdescribe()لتعيد"Car: [brand] with [doors] doors".main.php— قم بتضمين ملف Car. ستتلقى ثلاثة مدخلات: اسم العلامة التجارية، عدد الأبواب، وسلسلة نصية للموقع. أنشئ مثيلاً منCar، وقم بتعيين موقعه، ثم اطبع سطرين:- نتيجة استدعاء
describe() - نتيجة استدعاء
getLocation()
- نتيجة استدعاء
لاحظ كيف تعمل الوراثة والسمات معاً هنا: Car هو Vehicle (الوراثة تؤسس الهوية)، بينما Vehicle لديه قدرة تتبع (السمة تضيف السلوك). يمكنك استخدام instanceof Vehicle للتحقق مما إذا كان الشيء مركبة، ولكن لا يوجد نوع "Trackable" للتحقق منه — وهذا هو الفرق الجوهري بين هذين النهجين.
ورقة مرجعية
استخدم الوراثة (inheritance) لعلاقات "is-a" و السمات (traits) لقدرات "has-a".
تُحدد الوراثة الهوية - فالفئة الابنة هي نوع من الفئة الأب ويمكن استخدامها في أي مكان يُتوقع فيه وجود النوع الأب.
تضيف السمات سلوكاً دون تغيير هوية الفئة - فالفئة تمتلك وظيفة معينة ولكنها لا تصبح ذلك الشيء.
<?php
// الوراثة: الكلب هو حيوان (Dog IS an Animal)
class Animal {
public function breathe(): void {
echo "Breathing";
}
}
class Dog extends Animal {
public function bark(): void {
echo "Woof!";
}
}
// السمات: القطة لديها قدرة التسجيل (Cat HAS logging capability)
trait Loggable {
public function log(string $msg): void {
echo "Log: $msg";
}
}
class Cat extends Animal {
use Loggable;
}
| الجانب | الوراثة | السمات |
|---|---|---|
| العلاقة | is-a | قدرة has-a |
| الحد | أب واحد فقط | يُسمح بسمات متعددة |
| التحقق من النوع | يعمل مع instanceof | لا توجد هوية للنوع |
| الأفضل لـ | العلاقات الهرمية | السلوكيات المشتركة عبر فئات غير مرتبطة |
استخدم الوراثة للعلاقات الهرمية حيث تشترك الفئات في هوية مشتركة. استخدم السمات للسلوكيات المشتركة عبر فئات غير مرتبطة.
جرّب بنفسك
<?php
// الملف الرئيسي - إنشاء واختبار مثيل السيارة (Car)
// TODO: تضمين ملف Car.php
// قراءة المدخلات
$brand = trim(fgets(STDIN));
$doors = intval(trim(fgets(STDIN)));
$location = trim(fgets(STDIN));
// TODO: إنشاء مثيل للسيارة (Car) مع العلامة التجارية والأبواب
// TODO: تعيين موقع السيارة
// TODO: طباعة نتيجة describe()
// TODO: طباعة نتيجة getLocation()
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)9السمات (Traits)
مقدمة إلى السماتاستخدام سمات متعددةحل تعارض السماتالدوال المجردة في السماتالسمات مقابل الوراثة