PHP - Cloning Objects

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.

Example

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ó.

Example

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

Example

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
   )
)

Using the "clone" Keyword

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.

Example

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
   )
)

Using __clone() Method

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.

Example

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
   )
)