Php 简明教程

PHP - Cloning Objects

诸如“$obj1 = $obj2”的 PHP 语句只是创建对内存中同一对象的另一个引用。因此,属性的更改同时反映在原始对象和复制的对象中。PHP 中的 clone 关键字创建对象的浅拷贝。

$obj2 = $obj1

原始对象中的更改不会反映在浅拷贝中。

Example

请看以下示例:

<?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;
?>

它将生成以下 output

Hello Hello
Hello World Hello World

在第一种情况下, $y 只是 $x 的引用副本。因此, var1 属性的任何更改都会反映在两者中。

但是,如果我们将 $y 声明为 $x 的克隆,则原始对象中的任何更改都不会反映在其浅拷贝中。

Example

请看以下示例:

<?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;
?>

它将生成以下 output

Hello World Hello World
Hello PHP Hello World

Example

在以下代码中, myclass 的属性之一是作为地址类对象的属性。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;
      }
   }

   $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);
?>

它将生成以下 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

在浅表副本中,任何是对其他变量引用的原始对象的属性都将保持引用。clone 关键字不会复制复制对象的包含对象。

我们现在创建 myclass 对象的克隆,以便 $obj2$obj1 的克隆。我们将 $obj1 的 name 属性从 Raja 更改为 Ravi ,然后修改嵌入地址对象。属性更改不会反映在其克隆中,但是引用的地址对象将更改。

Example

请看以下示例:

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

它将生成以下 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

clone 关键字创建对象的浅表副本。克隆对象后,PHP 将对所有对象的属性执行浅表副本。是对其他变量引用的任何属性都将保持引用。因此,对原始对象执行的任何更改也将出现在克隆对象中。

如果您希望防止复制的对象自动更新,则需要使用 __clone() 方法创建对象的深表副本。它是 PHP 中的魔术方法之一。

一旦克隆完成,如果定义了 _clone() 方法,系统就会调用新创建对象的 _clone() 方法,以允许需要更改的任何必要属性。

Example

在上述示例中,我们有一个 myclass 对象,其中一个属性 $obj 保存对地址类的对象的引用。要实现深表副本,我们会覆盖 myclass 中的 __clone() 魔术方法。

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

您现在会看到原始对象(我们更改地址属性)中的更改不会反映在克隆对象中,如下面的 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
   )
)

Cloned object
myclass Object
(
   [name] => Raja
   [obj] => address Object
   (
      [city] => Nanded
      [pin] => 431601
   )
)