PHP

php使用clone总结

Posted by Alex Kinhoom on April 14, 2018

关键字clone

使用clone会复制出一个的对象。

class c1 {
    public $a1;
    public $a2;
}

$c1 = new c1;
$c1 -> a1 = 'a';
$c1 -> a2 = 'b';

$copy_c1 = $c1;
/*对象的赋值是引用赋值,$copy_c1与$c1指向的是同一地址*/
$clone_c1 = clone $c1;
/*clone会复制出一个新对象*/
echo "<span style='white-space:pre;'>";
var_dump($c1);
var_dump($copy_c1);
var_dump($clone_c1);

输出结果:

object(c1)#1 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  string(1) "b"
}
object(c1)#1 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  string(1) "b"
}
object(c1)#2 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  string(1) "b"
}

继续添加代码:

$c1 -> a1 = 'c';

var_dump($c1);
var_dump($copy_c1);
var_dump($clone_c1);

输出结果:

object(c1)#1 (2) {
  ["a1"]=>
  string(1) "c"
  ["a2"]=>
  string(1) "b"
}
object(c1)#1 (2) {
  ["a1"]=>
  string(1) "c"
  ["a2"]=>
  string(1) "b"
}
object(c1)#2 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  string(1) "b"
}

得出结论:实例化对象赋值为引用赋值,使用关键字clone可以完成对对象的复制得到新的独立的对象。

clone 方法

使用关键字 clone 克隆一个对象,新创建的对象复制生成的对象中的 __clone() 方法会被调用

class c1 {
    public $a1;
    public $a2;
    public function __clone() {
        $this -> a1 = 'x';
    }
}

$c1 = new c1;
$c1 -> a1 = 'a';
$c1 -> a2 = 'b';
var_dump($c1);
$c2 = clone $c1;
var_dump($c2);

打印结果:

object(c1)#1 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  string(1) "b"
}
object(c1)#2 (2) {
  ["a1"]=>
  string(1) "x"
  ["a2"]=>
  string(1) "b"
}

浅复制与深复制

class nc {
    public $na = 'm';
}
class tc {
    public $a1;
    public $a2;
}

$obj = new tc;
$obj -> a1 = 'a';
$obj -> a2 = new nc;
echo "<span style='white-space:pre'>";
var_dump($obj);
$copy_obj_new = clone $obj;
var_dump($copy_obj_new);
$copy_obj_new->a1='b';
$copy_obj_new->a2->na='n';
var_dump($copy_obj_new);
var_dump($obj);

输出:

object(tc)#1 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  object(nc)#2 (1) {
    ["na"]=>
    string(1) "m"
  }
}
object(tc)#3 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  object(nc)#2 (1) {
    ["na"]=>
    string(1) "m"
  }
}
object(tc)#3 (2) {
  ["a1"]=>
  string(1) "b"
  ["a2"]=>
  object(nc)#2 (1) {
    ["na"]=>
    string(1) "n"
  }
}
object(tc)#1 (2) {
  ["a1"]=>
  string(1) "a"
  ["a2"]=>
  object(nc)#2 (1) {
    ["na"]=>
    string(1) "n"
  }
}

结论:clone后属性值为非对象时,克隆前后是独立的,没有相互影响。属性值为对象时,对象的属性值仍然指向同一个变量的地址

解决浅复制

一种是使用__clone()方法此法不推荐,因为不适合批量操作,另一种是序列反序列

clone

class nc {
    public $na = 'm';
}
class tc {
    public $a1;
    public $a2;
    public function __clone(){
        $this->a2=clone new nc;
   }
}
$tc=new tc;
$tc->a1='a';
$tc->a2=new nc;
var_dump($tc);
var_dump(clone $tc);

输出结果:

object(tc)#1 (2) { ["a1"]=> string(1) "a" ["a2"]=> object(nc)#2 (1) { ["na"]=> string(1) "m" } } object(tc)#3 (2) { ["a1"]=> string(1) "a" ["a2"]=> object(nc)#5 (1) { ["na"]=> string(1) "m" } }

注意:产生#5而不是#4的原因是new classname生成#4,clone new classname便生成#5

serialize/unserialize

class newClass {
    public $newAttr = 'm';
}
class testClass {
    public $attr1;
    public $attr2;
}

$obj = new testClass();
$obj->attr1='a';
$obj->attr2=new newClass;
echo "<span style='white-space:pre'>";
var_dump($obj);
$newc=unserialize(serialize($obj));
var_dump($newc);

输出结果:

object(testClass)#1 (2) {
  ["attr1"]=>
  string(1) "a"
  ["attr2"]=>
  object(newClass)#2 (1) {
    ["newAttr"]=>
    string(1) "m"
  }
}
object(testClass)#3 (2) {
  ["attr1"]=>
  string(1) "a"
  ["attr2"]=>
  object(newClass)#4 (1) {
    ["newAttr"]=>
    string(1) "m"
  }
}

注意:unserialize产生的新的对象对应的地址是#3#4,而不是#3,#5