如何複製PHP對象的且更改值互不影響

今天在項目中有一個需求,需要複製一份DB類查詢出來的結果作爲原數據和新數據進行比較。

一開始我直接複製了一份:$walletInfoCopy = $walleltInfo;

但是問題是,如果$walletInfo中的值更改,那麼$walletInfoCopy中的值也會更改,後來發現只要實現PHP對象的完全深拷貝就可以實現這個需求。

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

  • 深拷貝:賦值時值完全複製,完全的copy,對其中一個作出改變,不會影響另一個
  • 淺拷貝:賦值時,引用賦值,相當於取了一個別名。對其中一個修改,會影響另一個

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

普通數據類型一般是深拷貝,而對象的深拷貝分爲三種,淺拷貝、部分深拷貝、完全深拷貝,下面一一介紹:

1、普通數據類型的深拷貝 ‘=’

<?php

//普通對象賦值,深拷貝,完全值複製
$m = 1;
$n = $m;
$n = 2;
echo $m;//值複製,對新對象的改變不會對m作出改變,輸出 1.深拷貝
echo PHP_EOL;
?>

2、對象的淺拷貝 ‘=’

//對象賦值,淺拷貝,引用賦值

class Test{

    public $a=1;

}

$m = new Test();

$n = $m;//引用賦值

$m->a = 2;//修改m,n也隨之改變

echo $n->a;//輸出2,淺拷貝

echo PHP_EOL;

?>

3、clone實現對象的部分深拷貝

由於對象的賦值時引用,要想實現值複製,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,實現賦值
 

來源:https://www.cnblogs.com/taijun/p/4208008.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章