1. 程式人生 > >php之clone 複製物件以及__clone魔術方法

php之clone 複製物件以及__clone魔術方法

如果錯誤和不足請給予指出,謝謝~

(⊙_⊙)

在開始使用clone之前我們下先看以下一個小例子:

<?php 
//首先定義一個test一個類
class Testclass {
    //成員變數是$value1
    public $value1;
}
//隨後new一個obj1
$obj1 = new Testclass();
//複製成員變數的值為qqq
$obj1->value1 = "qqq";
//我們使用賦值符號給左邊obj2賦值obj1
$obj2 = $obj1;
//我們在這裡把obj2的的value1複製為eee
$obj2->value1 ="eee";     
//隨後我們打印出兩者的值
var_dump($obj1); echo '<br/>'; var_dump($obj2);

為了檢視方便,我把那個解釋寫在了註釋=。=。(這句話總感覺怪怪的)

我們執行一下,發現如下結果:
執行結果

是不是兩者的值都是一樣的?
那是因為(借用php手冊的話就是):當物件被複制後,PHP 5 會對物件的所有屬性執行一個淺複製(shallow copy)。所有的引用屬性 仍然會是一個指向原來的變數的引用。

其實在這裡就是obj1給了obj2它的地址,就和引用一樣,obj2指向了obj1,所以導致兩者所執行的操作將會收到影響。那麼該如何解決這樣情況呢?當然是使用clone了;列如下程式碼:

<?php 
//首先定義一個test一個類
class Testclass {
    //成員變數是$value1
    public $value1;
}
//隨後new一個obj1
$obj1 = new Testclass();
//複製成員變數的值為qqq
$obj1->value1 = "qqq";
//在這裡我們使用clone來賦值obj1
$obj2 =clone $obj1;
//我們在這裡把obj2的的value1複製為eee
$obj2->value1 ="eee";     
//隨後我們打印出兩者的值
var_dump($obj1);
echo '<br/>'
; var_dump($obj2);

注意看這一段程式碼:

$obj2 =clone $obj1;

在這裡使用了clone,這樣就會沒事了,看如下執行結果:
執行結果

是否發現兩者並沒有相互影響呢?

好了,在這裡已經完成了基本的clone的講解了,現在我們來深入一下(抽根菸壓壓驚。。。 ( ´´ิ∀´ิ` ) )

我們接下來看看一個例子:

<?php 
//首先定義一個test一個類
class Testclass {
    //成員變數是$value1
    public $value1;
}
//在這裡是定義了一個變數
$vlaue_1='bbj';
//隨後new一個obj1
$obj1 = new Testclass();
//引用value_1的值,注意,是引用
$obj1->value1 = &$vlaue_1;
//在這裡我們使用clone來賦值obj1
$obj2 =clone $obj1;
//我們在這裡把obj2的的value1複製為eee
$obj2->value1 ="eee";     
//隨後我們打印出兩者的值
var_dump($obj1);
echo '<br/>';
var_dump($obj2);

我們的程式碼和之前的差不多,我們主要看這一行:

//引用value_1的值,注意,是引用
$obj1->value1 = &$vlaue_1;

注意在此是引用喲。
我們看下執行結果:
執行結果
是否發現我在obj2改變了value1值之後obj1的值也會改變?因為在這裡obj1賦值成員變數的時候使用了&取址。將會成為一個引用的狀態。那麼我們如果想要把這個值不守clone出來的物件的值影響該怎麼辦呢?

那麼在這裡我們只需要在此clone一下這個成員變數就好了,該如何clone了?那麼我們現在就可以使用我們的魔法方法__clone了。

首先我們來說說__clone()在什麼狀態下觸發:

當我們有clone操作的時候將會除非這個類裡面的__clone方法。那麼把我們的成員變數在__clone方法裡面clone一下就好了,如下程式碼演示:
注:clone只能用於物件克隆,物件複製。記住,如果你clone一個非物件變數將會報錯no obj。。。
以下例子是我從網上找的一個例子,感覺不錯,這裡將用這個例子來講解魔法方法__clone的使用:
本來這個是沒有註釋的,我順便把解釋丟到了裡面,這樣強制clone後就不會指向原來的物件了。

<?php 
class testClass
{
 public $str_data;//這裡是一個非物件型別
 public $obj_data;//在這裡這是一個物件,可以看下面將會給一個物件給他
//使用clone的時候觸發
 public function __clone() {
   $this->obj_data = clone $this->obj_data;//這個物件將會被克隆,會被強制複製,這樣就不會指向原來的物件了
 }
}
//new一個datatime對給datatimeobj
$dateTimeObj = new DateTime("2014-07-05", new DateTimeZone("UTC"));

$obj1 = new testClass();//new一個testclass
$obj1->str_data ="aaa"; //複製aaa
$obj1->obj_data = $dateTimeObj; //給obj_data一個物件datetimeobj

$obj2 = clone $obj1; //克隆obj1給obj2
var_dump($obj1);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
var_dump($obj2);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
$obj2->str_data ="bbb"; //obj2給一個值bbb給strdata
$obj2->obj_data->add(new DateInterval('P10D'));//objdata改變objdata的值

var_dump($obj1);  // str_data:"aaa"  obj_data:"2014-07-05 00:00:00"
var_dump($obj2);  // str_data:"aaa"  obj_data:"2014-07-15 00:00:00"
var_dump($dateTimeObj);  //"2014-07-05 00:00:00"

以上就是clone的使用方法了=。=。。。
如果錯誤請給予指出,謝謝~