บทนำ
การสร้างสำเนาออบเจ็กต์ด้วยการกำหนดค่า (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 Properties | Object Properties | ใช้เมื่อไหร่ |
|---|---|---|---|
| Assignment (=) | Shared Reference | Shared Reference | ต้องการ Reference เดียวกัน |
| clone (Shallow) | Copied Value | Shared Reference | ไม่มี Embedded Objects หรือต้องการ Share Embedded |
| clone + __clone() (Deep) | Copied Value | Copied Object | ต้องการอิสระสมบูรณ์ (Deep Copy) |