تعمق في استنساخ الكائنات
جزء من قسم البرمجة كائنية التوجه في رحلة PHP على Coddy. الدرس 61 من 91.
تعرّفتَ في وقت سابق من هذه الدورة التدريبية على __clone magic method. والآن لنستكشف الفرق الجوهري بين الاستنساخ السطحي والاستنساخ العميق عندما تحتوي الكائنات على كائنات أخرى بوصفها خصائص.
بشكل افتراضي، تنفّذ PHP نسخة سطحية عند الاستنساخ. تُكرَّر القيم العددية، لكن تظل خصائص الكائنات مراجع إلى الكائنات نفسها:
<?php
class Address {
public function __construct(public string $city) {}
}
class Person {
public function __construct(
public string $name,
public Address $address
) {}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->name = "Bob";
$clone->address->city = "London";
echo $original->name . " - " . $original->address->city;
الناتج:
Alice - Londonلاحظ أن تغيير $clone->name لم يؤثر في original، لكن تغيير مدينة العنوان فعل ذلك! يشترك الكائنان في مثيل Address نفسه.
لإنشاء نسخة عميقة حيث يتم أيضًا استنساخ الكائنات المتداخلة، نفّذ __clone:
<?php
class Person {
public function __construct(
public string $name,
public Address $address
) {}
public function __clone(): void {
$this->address = clone $this->address;
}
}
$original = new Person("Alice", new Address("Paris"));
$clone = clone $original;
$clone->address->city = "London";
echo $original->address->city;
الناتج:
Parisالآن أصبح لكل Person Address مستقل خاص به. عندما تحتوي كائناتك على عدة كائنات متداخلة، يجب عليك استنساخ كل منها في __clone لتحقيق استقلال حقيقي بين original والنسخة.
التحدي
سهللنَبْنِ نظامًا لإدارة المستندات يوضّح الفرق بين الاستنساخ السطحي والاستنساخ العميق. ستنشئ مستندات تحتوي على معلومات المؤلف، وتضمن أن يؤدي استنساخ المستند إلى إنشاء نسخة مستقلة حقًا.
ستنظّم الشيفرة عبر ثلاثة ملفات:
Author.php: أنشئ فئةAuthorتمثّل author الخاص بالمستند. استخدم ترقية المُنشئ لتعريف$nameعام (من النوع string) و$emailعام (من النوع string).Document.php: أنشئ فئةDocumentتحتوي على author. أدرِج ملف Author. يجب أن تقوم الفئة بما يلي:- استخدم ترقية المُنشئ من أجل
$titleعام (من النوع string) و$authorعام (من النوع Author) - نفّذ الطريقة السحرية
__clone()لإجراء استنساخ عميق؛ فعند استنساخ مستند، يجب أيضًا استنساخ author الخاص به حتى لا تؤثر التغييرات على author الخاص بالنسخة في المستند الأصلي - احتوِ على method باسم
getInfo()يعيد"[title] by [author name] ([author email])"
- استخدم ترقية المُنشئ من أجل
main.php: أدرِج ملف Document. ستتلقى ثلاثة inputs: عنوان مستند، واسم author، وبريد author الإلكتروني.أنشئ
DocumentمعAuthorباستخدام inputs المقدمة. استنسخ المستند، ثم عدّل اسم author الخاص بالنسخة بإلحاق" (Copy)"به، وغيّر عنوان النسخة بإضافة"Copy of "في بدايته.اطبع سطرين:
- info الخاص بالمستند الأصلي
- info الخاص بالمستند المستنسخ
إذا نُفّذ الاستنساخ العميق بشكل صحيح، فيجب أن يظل author الخاص بالمستند الأصلي دون تغيير حتى بعد تعديل author الخاص بالنسخة.
يوضّح هذا التحدي سبب أهمية الاستنساخ العميق؛ فبدون التنفيذ الصحيح لـ __clone()، سيشترك المستندان في كائن Author نفسه، وسيؤثر تغيير أحدهما في الآخر.
جرّب بنفسك
<?php
require_once 'Document.php';
// قراءة المدخلات
$title = trim(fgets(STDIN));
$authorName = trim(fgets(STDIN));
$authorEmail = trim(fgets(STDIN));
// TODO: أنشئ Author بالاسم والبريد الإلكتروني المقدمين
// TODO: أنشئ Document بالعنوان المقدم و Author
// TODO: استنسخ المستند
// TODO: عدّل اسم مؤلف النسخة بإلحاق " (Copy)" به
// TODO: عدّل عنوان النسخة بإضافة "Copy of " في بدايته
// TODO: اطبع معلومات المستند الأصلي
// TODO: اطبع معلومات المستند المستنسخ
?>يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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)تدرّب بنفسك: مترجم PHP عبر الإنترنت