Một câu lệnh PHP như "$obj1 = $obj2" chỉ đơn giản tạo ra một tham chiếu khác đến cùng một đối tượng trong bộ nhớ. Do đó, những thay đổi trong thuộc tính sẽ phản ánh cả ở đối tượng gốc và đối tượng sao chép. Từ khóa clone trong PHP tạo ra một bản sao nông của một đối tượng.
$obj2 = $obj1
Những thay đổi trong đối tượng gốc không được phản ánh trong bản sao nông.
Hãy xem ví dụ sau đây −
<?php class foo { var $var1 = 'Hello'; } $x = new foo(); $y = $x; # reference copy echo $x->var1 . " " . $y->var1 . PHP_EOL; $x->var1 = "Hello World"; echo $x->var1 . " " . $y->var1 . PHP_EOL; ?>
Nó sẽ tạo ra output −
Hello Hello Hello World Hello World
Trong trường hợp đầu tiên, $y chỉ là một bản sao tham chiếu của $x . Do đó, bất kỳ thay đổi nào trong thuộc tính var1 đều phản ánh ở cả hai.
Tuy nhiên, nếu chúng ta khai báo $y là một bản sao của $x , thì bất kỳ thay đổi nào trong đối tượng gốc sẽ không được phản ánh trong bản sao nông của nó.
Hãy xem ví dụ sau đây −
<?php class foo { var $var1 = 'Hello World'; } $x = new foo(); # shallow copy $y = clone $x; echo $x->var1 . " " . $y->var1 . PHP_EOL; $x->var1 = "Hello PHP"; echo $x->var1 . " " . $y->var1 . PHP_EOL; ?>
Nó sẽ tạo ra output −
Hello World Hello World Hello PHP Hello World
Trong đoạn mã sau, myclass có một trong những thuộc tính là đối tượng của lớp address. Một đối tượng của myclass được sao chép bằng phép gán. Bất kỳ thay đổi nào trong giá trị của đối tượng address nhúng đều được phản ánh trong cả hai đối tượng, nhưng thay đổi trong thuộc tính name sẽ không ảnh hưởng đến đối tượng đã sao chép.
<?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); echo "\n"; $obj2=$obj1; # reference copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCopied object\n"; print_r($obj2); ?>
Nó sẽ tạo ra output −
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 ) ) Copied object myclass Object ( [name] => Ravi [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) )
Trong một bản sao nông, bất kỳ thuộc tính nào của đối tượng gốc mà là tham chiếu đến các biến khác sẽ vẫn giữ nguyên tham chiếu. Từ khóa clone không sao chép các đối tượng chứa bên trong các đối tượng đã sao chép.
Chúng tôi bây giờ tạo một bản sao của đối tượng myclass, để $obj2 là bản sao của $obj1 . Chúng tôi thay đổi thuộc tính tên của $obj1 từ Raja thành Ravi , và cũng sửa đổi đối tượng địa chỉ nhúng. Sự thay đổi thuộc tính sẽ không phản ánh trong bản sao của nó, nhưng đối tượng địa chỉ được tham chiếu sẽ bị thay đổi.
Hãy xem ví dụ sau đây −
<?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); echo "\n"; $obj2=clone $obj1; # clone copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCopied object\n"; print_r($obj2); ?>
Nó sẽ tạo ra output −
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 ) ) Copied object myclass Object ( [name] => Raja [obj] => address Object ( [city] => Mumbai [pin] => 400001 ) )
Từ khóa clone tạo ra một bản sao nông của đối tượng. Khi một đối tượng được nhân bản, PHP sẽ thực hiện một bản sao nông của tất cả các thuộc tính của đối tượng. Bất kỳ thuộc tính nào là tham chiếu đến các biến khác sẽ vẫn giữ nguyên tham chiếu. Do đó, bất kỳ thay đổi nào được thực hiện trên đối tượng gốc cũng sẽ xuất hiện trong đối tượng đã nhân bản.
Nếu bạn muốn ngăn chặn đối tượng đã sao chép cập nhật tự động, chúng ta cần tạo một bản sao sâu của đối tượng bằng phương thức __clone(). Đây là một trong những phương thức ma thuật trong PHP.
Khi việc sao chép hoàn tất, nếu một phương thức __clone() được định nghĩa, thì phương thức __clone() của đối tượng mới tạo ra sẽ được gọi, để cho phép thay đổi bất kỳ thuộc tính nào cần thiết.
Trong ví dụ trên, chúng ta có một đối tượng của myclass, một trong những thuộc tính của nó là $obj giữ tham chiếu đến một đối tượng của lớp address. Để thực hiện sao chép sâu, chúng ta ghi đè phương thức ma thuật __clone() trong myclass.
<?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 ; } } $obj1=new myclass(); $obj1->obj=new address(); echo "original object\n"; print_r($obj1); echo "\n"; $obj2=clone $obj1; # cloned deep copy $obj1->setname("Ravi"); $obj1->obj->setaddr("Mumbai", "400001"); echo "after change: Original object\n"; print_r($obj1); echo "\nCloned object\n"; print_r($obj2); ?>
Bạn sẽ thấy rằng những thay đổi trong đối tượng gốc (chúng ta thay đổi thuộc tính địa chỉ) sẽ không phản ánh trong đối tượng đã sao chép, như output sau đây cho thấy −
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 ) )