مقدمة إلى السمات
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 51 من 91.
يدعم PHP الوراثة الفردية فقط - حيث يمكن للفئة (class) أن ترث من فئة أب واحدة فقط. ولكن ماذا لو كنت بحاجة إلى مشاركة الوظائف عبر فئات متعددة غير مرتبطة؟ هنا يأتي دور الـ traits.
السمة (trait) هي آلية لإعادة استخدام الكود تتيح لك تعريف الدوال (methods) والخصائص (properties) التي يمكن إدراجها في فئات (classes) متعددة. فكر في السمات (traits) كعملية نسخ ولصق على مستوى اللغة - حيث يصبح الكود الخاص بالسمة جزءاً من الفئة التي تستخدمها.
<?php
trait Timestampable {
private string $createdAt;
public function setCreatedAt(): void {
$this->createdAt = date('Y-m-d H:i:s');
}
public function getCreatedAt(): string {
return $this->createdAt;
}
}
class Article {
use Timestampable;
public function __construct(public string $title) {
$this->setCreatedAt();
}
}
$article = new Article("PHP Traits");
echo $article->getCreatedAt();
تستورد الكلمة المفتاحية use داخل الفئة (class) أعضاء الـ trait. الآن، أصبح لدى Article إمكانية الوصول إلى setCreatedAt() و getCreatedAt() كما لو تم تعريفهما مباشرة في الفئة.
يمكن استخدام نفس الـ trait في فئات غير مرتبطة تماماً - فئة Comment، أو فئة User، أو أي فئة أخرى تحتاج إلى وظيفة الطابع الزمني (timestamp). هذا يحل محدودية الوراثة الأحادية من خلال السماح بمشاركة الكود بشكل أفقي عبر التسلسل الهرمي للفئات الخاصة بك.
التحدي
سهللنقم ببناء نظام ترحيب بسيط يوضح كيف تسمح لك السمات (traits) بمشاركة الوظائف عبر فئات (classes) غير مرتبطة. ستقوم بإنشاء سمة توفر إمكانية الترحيب، ثم تستخدمها في فئتين مختلفتين تماماً.
ستقوم بتنظيم الكود الخاص بك عبر ثلاثة ملفات:
Greetable.php— أنشئ سمة تسمىGreetableتوفر وظيفة الترحيب. يجب أن تحتوي السمة على:- خاصية خاصة
$greeting(سلسلة نصية string) - دالة
setGreeting(string $greeting)تقوم بتخزين رسالة الترحيب - دالة
greet()تقوم بإرجاع رسالة الترحيب
- خاصية خاصة
Person.php— أنشئ فئةPersonتستخدم سمةGreetable. قم بتضمين ملف السمة واستخدم خاصية الترويج في المنشئ (constructor promotion) لتعريف خاصية عامة$name. في المنشئ، استدعِsetGreeting()لضبط الترحيب على"Hello, I'm [name]".Robot.php— أنشئ فئةRobotتستخدم أيضاً سمةGreetable. قم بتضمين ملف السمة واستخدم خاصية الترويج في المنشئ لتعريف خاصية عامة$model. في المنشئ، استدعِsetGreeting()لضبط الترحيب على"Beep boop, I am model [model]".
في main.php، قم بتضمين ملفي الفئتين. ستتلقى مدخلين: اسم شخص ورقم طراز روبوت. أنشئ مثيلات (instances) من كلتا الفئتين واطبع ترحيباتهما في أسطر منفصلة.
يوضح هذا قوة السمات (traits) — حيث أن Person و Robot فئتان غير مرتبطتين تماماً ولا يوجد بينهما أب مشترك، ومع ذلك تكتسب كلتاهما نفس وظيفة الترحيب من خلال السمة. تقوم كل فئة بتخصيص كيفية استخدام هذه الوظيفة بطريقتها الخاصة.
ورقة مرجعية
الـ trait هي آلية لإعادة استخدام الكود تتيح لك مشاركة الأساليب (methods) والخصائص (properties) عبر فئات (classes) متعددة غير مرتبطة، مما يحل مشكلة قيود الوراثة الأحادية في لغة PHP.
قم بتعريف trait باستخدام الكلمة المفتاحية trait:
<?php
trait Timestampable {
private string $createdAt;
public function setCreatedAt(): void {
$this->createdAt = date('Y-m-d H:i:s');
}
public function getCreatedAt(): string {
return $this->createdAt;
}
}
استخدم trait داخل فئة (class) باستخدام الكلمة المفتاحية use:
class Article {
use Timestampable;
public function __construct(public string $title) {
$this->setCreatedAt();
}
}
تصبح أساليب وخصائص الـ trait جزءاً من الفئة كما لو تم تعريفها مباشرة داخلها. يمكن لفئات متعددة غير مرتبطة استخدام نفس الـ trait لمشاركة الوظائف بشكل أفقي عبر التسلسل الهرمي للفئات لديك.
جرّب بنفسك
<?php
require_once 'Person.php';
require_once 'Robot.php';
// قراءة المدخلات
$name = trim(fgets(STDIN));
$model = trim(fgets(STDIN));
// TODO: مع الاسم المعطى Person قم بإنشاء كائن من الفئة
// TODO: مع الطراز المعطى Robot قم بإنشاء كائن من الفئة
// TODO: Person اطبع تحية الـ
// TODO: (على سطر جديد) Robot اطبع تحية الـ
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس 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)
مقدمة إلى السماتاستخدام سمات متعددةحل تعارض السماتالدوال المجردة في السماتالسمات مقابل الوراثة