深拷貝和淺拷貝的概念,一般程式設計師都很熟悉,網上的概念解析也很多。可以檢視http://cnn237111.blog.51cto.com/2359144/589507。
PHP中提供了一種物件複製的操作,clone。語法頗為簡單:
$a = clone $b;
這時候就得到a物件就複製了b物件。如果b物件中的成員都是值型別,那也就沒什麼關係,a物件中的成員和b變數中的成員都是各自佔用獨立的記憶體空間。但是由於這個克隆操作是淺拷貝,所以如果b的成員中有引用型別的資料,那麼a物件的成員並未真正複製該成員,而是和b物件的成員共享了這一個物件。看下面的示例。
<?php class A { public $info="this is a"; } class B { public $a; function __construct() { $this->a=new A; } public $info="this is b"; } $b1=new B(); echo "clone操作<br>"; $b2=clone $b1; echo"b1的值<br>"; echo "b1的info:{$b1->info}<br>"; echo "b1的a的info:{$b1->a->info}<br><br>"; echo"b2的值<br>"; echo "b2的info:{$b2->info}<br>"; echo "b2的a的info:{$b2->a->info}<br><br>"; $b1->info="this value is updated(this is b)"; $b1->a->info="this value is updated(this is a)"; echo"修改b1後,b1的值<br>"; echo "b1的info:{$b1->info}<br>"; echo "b1的a的info:{$b1->a->info}<br><br>"; echo"修改b1後,b2的值<br>"; echo "b2的info:{$b2->info}<br>"; echo "b2的a的info:{$b2->a->info}<br><br>"; echo"判斷b1的a和b2的a是否為同一物件:" ,$b1->a===$b2->a; ?>
執行結果如下:
clone操作
b1的值
b1的info:this is b
b1的a的info:this is a
b2的值
b2的info:this is b
b2的a的info:this is a
修改b1後,b1的值
b1的info:this value is updated(this is b)
b1的a的info:this value is updated(this is a)
修改b1後,b2的值
b2的info:this is b
b2的a的info:this value is updated(this is a)
判斷b1的a和b2的a是否為同一物件:1
可以看到,修改b1中引用型別a的值後,b2中的a的值也跟著變了。進一步,可以判斷出b1的a和b2的a是同一個物件。
和C++一樣,php也提供了拷貝建構函式,以此可以自定義複製行為,實現深拷貝。PHP通過在物件的定義中實現__clone()方法來完成拷貝建構函式。這個函式在物件被複制的時候呼叫。還是之前的程式碼,修改一下。
<?php class A { public $info="this is a"; } class B { public $a; function __construct() { $this->a=new A; } public $info="this is b"; public function __clone() { echo "拷貝建構函式開始呼叫<br>"; $new_object=new A; $new_object->info=$this->a->info; $this->a=$new_object; } } $b1=new B(); echo "clone操作<br>"; $b2=clone $b1; echo "b1的值<br>"; echo "b1的info:{$b1->info}<br>"; echo "b1的a的info:{$b1->a->info}<br><br>"; echo"b2的值<br>"; echo "b2的info:{$b2->info}<br>"; echo "b2的a的info:{$b2->a->info}<br><br>"; $b1->info="this value is updated(this is b)"; $b1->a->info="this value is updated(this is a)"; echo"修改b1後,b1的值<br>"; echo "b1的info:{$b1->info}<br>"; echo "b1的a的info:{$b1->a->info}<br><br>"; echo"修改b1後,b2的值<br>"; echo "b2的info:{$b2->info}<br>"; echo "b2的a的info:{$b2->a->info}<br><br>"; echo"判斷b1的a和b2的a是否為同一物件:" ,$b1->a===$b2->a; ?>
執行完畢後,
clone操作
拷貝建構函式開始呼叫
b1的值
b1的info:this is b
b1的a的info:this is a
b2的值
b2的info:this is b
b2的a的info:this is a
修改b1後,b1的值
b1的info:this value is updated(this is b)
b1的a的info:this value is updated(this is a)
修改b1後,b2的值
b2的info:this is b
b2的a的info:this is a
判斷b1的a和b2的a是否為同一物件:
最後可以看到,b1的a和b2的a同一個物件是false,所以列印了一個空字串。
————————————————————————
上面的方法實現了魔法方法__clone,在這個方法中定義自己的深拷貝方式,這種寫法比較麻煩,如果物件修改了,這個方法也得修改。事實上對成員進行深拷貝,可以採用將物件序列化後再還原的方式。這種寫法可能效能上有所損失,但是確實最便捷的。PHP中,使用如下語句實現深拷貝:
$b2 = unserialize(serialize($b1));//序列化然後反序列化