Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> PHP

การโคลนออบเจ็กต์ (Object Cloning) ใน PHP

บทนำ

การสร้างสำเนาออบเจ็กต์ด้วยการกำหนดค่า (Assignment) เพียงอย่างเดียว จะสร้าง Reference ใหม่ที่ชี้ไปยังออบเจ็กต์เดิมในหน่วยความจำ การเปลี่ยนแปลง Attribute จะสะท้อนในทั้งสองตัว PHP มีคีย์เวิร์ด clone ที่สร้าง Shallow Copy (สำเนาลึก) แต่ถ้าออบเจ็กต์ต้นฉบับมีออบเจ็กต์อื่นฝังอยู่เป็น Property สำเนาจะยังอ้างอิงออบเจ็กต์ฝังอยู่เดิมกันอยู่ เพื่อสร้าง Deep Copy ต้องกำหนด Magic Method __clone()

1. Copy by Assignment (Reference Copy)

การกำหนดค่าทั่วไป สร้าง Reference ใหม่:

<?php
class address {
    var $city = "Nanded";
    var $pin = "431601";
    function setaddr($arg1, $arg2) {
        $this->city = $arg1;
        $this->pin = $arg2;
    }
}

class myclass {
    var $name = "Raja";
    var $obj;
    function setname($arg) {
        $this->name = $arg;
    }
}

$obj1 = new myclass();
$obj1->obj = new address();
echo "original object\n";
print_r($obj1);

$obj2 = $obj1;  // Assignment - Reference Copy
$obj1->setname("Ravi");
echo "after change:\n";
print_r($obj1);
print_r($obj2);
?>

ผลลัพธ์

original object
myclass Object(
    [name] => Raja
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)
after change:
original object
myclass Object(
    [name] => Ravi
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)
copied object
myclass Object(
    [name] => Ravi
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)

ทั้ง $obj1 และ $obj2 ชี้ไปยังออบเจ็กต์เดียวกัน การเปลี่ยน name ใน $obj1 ส่งผลต่อ $obj2 ด้วย

2. ใช้ clone Keyword (Shallow Copy)

clone สร้าง Shallow Copy - Properties แบบ Primitive จะคัดลอกค่า แต่ Properties ที่เป็น Object จะยัง Reference เดียวกัน:

<?php
class address {
    var $city = "Nanded";
    var $pin = "431601";
    function setaddr($arg1, $arg2) {
        $this->city = $arg1;
        $this->pin = $arg2;
    }
}

class myclass {
    var $name = "Raja";
    var $obj;
    function setname($arg) {
        $this->name = $arg;
    }
}

$obj1 = new myclass();
$obj1->obj = new address();
echo "original object:\n";
print_r($obj1);

$obj2 = clone $obj1;  // Shallow Copy
$obj1->setname("Ravi");
$obj1->obj->setaddr("Mumbai", "400001");
echo "after change:\n";
echo "original object:\n";
print_r($obj1);
echo "cloned object:\n";
print_r($obj2);
?>

ผลลัพธ์

original object:
myclass Object(
    [name] => Raja
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)
after change:
original object:
myclass Object(
    [name] => Ravi
    [obj] => address Object(
        [city] => Mumbai
        [pin] => 400001
    )
)
cloned object:
myclass Object(
    [name] => Raja
    [obj] => address Object(
        [city] => Mumbai
        [pin] => 400001
    )
)

$obj2->name ไม่เปลี่ยน (Primitive คัดลอกค่า) แต่ $obj2->obj ยังชี้ไป address เดียวกัน (Object Reference)

3. ใช้ __clone() Method (Deep Copy)

กำหนด __clone() เพื่อ Clone Embedded Objects ด้วย:

<?php
class address {
    var $city = "Nanded";
    var $pin = "431601";
    function setaddr($arg1, $arg2) {
        $this->city = $arg1;
        $this->pin = $arg2;
    }
}

class myclass {
    var $name = "Raja";
    var $obj;
    function setname($arg) {
        $this->name = $arg;
    }
    public function __clone() {
        $this->obj = clone $this->obj;  // Deep Copy embedded object
    }
}

$obj1 = new myclass();
$obj1->obj = new address();
echo "original object:\n";
print_r($obj1);

$obj2 = clone $obj1;
$obj1->setname("Ravi");
$obj1->obj->setaddr("Mumbai", "400001");
echo "after change:\n";
echo "original object:\n";
print_r($obj1);
echo "cloned object:\n";
print_r($obj2);
?>

ผลลัพธ์

original object:
myclass Object(
    [name] => Raja
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)
after change:
original object:
myclass Object(
    [name] => Ravi
    [obj] => address Object(
        [city] => Mumbai
        [pin] => 400001
    )
)
cloned object:
myclass Object(
    [name] => Raja
    [obj] => address Object(
        [city] => Nanded
        [pin] => 431601
    )
)

ตอนนี้ $obj2->obj เป็นออบเจ็กต์แยกต่างหาก การเปลี่ยนแปลงใน $obj1->obj ไม่ส่งผลต่อ $obj2->obj

สรุปการเปรียบเทียบ

วิธีPrimitive PropertiesObject Propertiesใช้เมื่อไหร่
Assignment (=)Shared ReferenceShared Referenceต้องการ Reference เดียวกัน
clone (Shallow)Copied ValueShared Referenceไม่มี Embedded Objects หรือต้องการ Share Embedded
clone + __clone() (Deep)Copied ValueCopied Objectต้องการอิสระสมบูรณ์ (Deep Copy)