首頁  >  文章  >  後端開發  >  php中深拷貝和淺拷貝的差別是什麼

php中深拷貝和淺拷貝的差別是什麼

WBOY
WBOY原創
2022-02-10 09:53:472663瀏覽

PHP中深拷貝和淺拷貝的區別:1、深拷貝賦值時是完全複製,而淺拷貝只是引用賦值,相當於取了一個別名;2、深拷貝若對其中一個做出改變不會影響另一個,而淺拷貝對其中一個進行修改會影響另一個。

php中深拷貝和淺拷貝的差別是什麼

本教學操作環境:windows10系統、PHP7.1版、DELL G3電腦

php中深拷貝和淺拷貝的差異是什麼

先說一下深拷貝和淺拷貝通俗理解

深拷貝:賦值時值完全複製,完全的copy,對其中一個作出改變,不會影響另一個

淺拷貝:賦值時,引用賦值,相當於取了一個別名。對其中一個修改,會影響另一個

PHP中, = 賦值時,普通物件是深拷貝,但對物件來說,是淺拷貝。也就是說,物件的賦值是引用賦值。 (當物件作為參數傳遞時,也是引用傳遞,無論函數定義時參數前面是否有&符號)

php4中,物件的= 賦值是實現一份副本,這樣存在很多問題,在不知不覺中我們可能會拷貝很多份副本。

php5中,物件的 = 賦值和傳遞都是參考。要實現拷貝副本,php提供了clone函數實作。

clone完全copy了一份副本。但是clone時,我們可能不希望copy來源物件的所有內容,那我們可以利用__clone來操作。

在__clone()中,我們可以做一些操作。注意,這些操作,也就是__clone函數是作用於拷貝的副本物件上的

<?php
//普通对象赋值,深拷贝,完全值复制
$m = 1;
$n = $m;
$n = 2;
echo $m;//值复制,对新对象的改变不会对m作出改变,输出 1.深拷贝
echo PHP_EOL;
/*==================*/
 
//对象赋值,浅拷贝,引用赋值
class Test{
    public $a=1;
}
$m = new Test();
$n = $m;//引用赋值
$m->a = 2;//修改m,n也随之改变
echo $n->a;//输出2,浅拷贝
echo PHP_EOL;
?>

  由於物件的賦值時引用,要想實現值複製,php提供了clone函數來實現複製物件。

但是clone函數有這麼一個問題,當克隆物件時,原始物件的普通屬性能值複製,但是來源物件的物件屬性賦值時還是引用賦值,淺拷貝。

<?php
class Test{
    public $a=1;
}
 
class TestOne{
    public $b=1;
    public $obj;
    //包含了一个对象属性,clone时,它会是浅拷贝
    public function __construct(){
        $this->obj = new Test();
    }
}
$m = new TestOne();
$n = $m;//这是完全的浅拷贝,无论普通属性还是对象属性
 
$p = clone $m;
 
//普通属性实现了深拷贝,改变普通属性b,不会对源对象有影响
$p->b = 2;
echo $m->b;//输出原来的1
echo PHP_EOL;
 
//对象属性是浅拷贝,改变对象属性中的a,源对象m中的对象属性中a也改变
 
$p->obj->a = 3;
echo $m->obj->a;//输出3,随新对象改变
?>

  要想實現物件真正的深拷貝,有以下兩種方法:

寫clone函數:如下

<?php
class Test{
    public $a=1;
}
 
class TestOne{
    public $b=1;
    public $obj;
    //包含了一个对象属性,clone时,它会是浅拷贝
    public function __construct(){
        $this->obj = new Test();
    }
     
    //方法一:重写clone函数
    public function __clone(){
        $this->obj = clone $this->obj;
    }
}
 
$m = new TestOne();
$n = clone $m;
 
$n->b = 2;
echo $m->b;//输出原来的1
echo PHP_EOL;
//可以看到,普通属性实现了深拷贝,改变普通属性b,不会对源对象有影响
 
//由于改写了clone函数,现在对象属性也实现了真正的深拷贝,对新对象的改变,不会影响源对象
$n->obj->a = 3;
echo $m->obj->a;//输出1,不随新对象改变,还是保持了原来的属性
 
?>

  改寫__clone()函數不太方便,而且你得在每個類別中把這個類別裡面的物件屬性都在__clone()中一一clone

#第二種方法,利用序列化反序列化實現,這種方法實現物件的深拷貝簡單,不需要修改類別

<?php
class Test{
    public $a=1;
}
 
class TestOne{
    public $b=1;
    public $obj;
    //包含了一个对象属性,clone时,它会是浅拷贝
    public function __construct(){
        $this->obj = new Test();
    }
     
}
 
$m = new TestOne();
//方法二,序列化反序列化实现对象深拷贝
$n = serialize($m);
$n = unserialize($n);
 
$n->b = 2;
echo $m->b;//输出原来的1
echo PHP_EOL;
//可以看到,普通属性实现了深拷贝,改变普通属性b,不会对源对象有影响
 
 
$n->obj->a = 3;
echo $m->obj->a;//输出1,不随新对象改变,还是保持了原来的属性,可以看到,序列化和反序列化可以实现对象的深拷贝
 
?>

 還有第三種方法,其實和第二種類似,json_encode之後再json_decode,實作賦值

推薦學習:《PHP影片教學

以上是php中深拷貝和淺拷貝的差別是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn