Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

تعمق في استنساخ الكائنات

جزء من قسم البرمجة كائنية التوجه في رحلة 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 والنسخة.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لإدارة المستندات يوضّح الفرق بين الاستنساخ السطحي والاستنساخ العميق. ستنشئ مستندات تحتوي على معلومات المؤلف، وتضمن أن يؤدي استنساخ المستند إلى إنشاء نسخة مستقلة حقًا.

ستنظّم الشيفرة عبر ثلاثة ملفات:

  • 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: اطبع معلومات المستند المستنسخ

?>
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم PHP عبر الإنترنت