深拷貝和淺拷貝的概念,一般程式員都很熟悉,網上的概念解析也很多。可以查看http://cnn237111.blog.51cto.com/2359144/589507。
PHP中提供了一直對象複製的操作,clone。文法頗為簡單:
$a = clone $b;
這時候就得到a對象就複製了b對象。如果b對象中的成員都是實值型別,那也就沒什麼關係,a對象中的成員和b變數中的成員都是各自佔用獨立的記憶體空間。但是由於這個複製操作是淺拷貝,所以如果b的成員中有參考型別的資料,那麼a對象的成員並未真正複製該成員,而是和b對象的成員共用了這一個對象。看下面的樣本。
<?phpclass 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()方法來完成拷貝建構函式。這個函數在對象被複製的時候調用。還是之前的代碼,修改一下。
<?phpclass 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,所以列印了一個Null 字元串。
————————————————————————
上面的方法實現了魔法方法__clone,在這個方法中定義自己的深拷貝方式,這種寫法比較麻煩,如果對象修改了,這個方法也得修改。事實上對成員進行深拷貝,可以採用將對象序列化後再還原的方式。這種寫法可能效能上有所損失,但是確實最便捷的。PHP中,使用如下語句實現深拷貝:
$b2 = unserialize(serialize($b1));//序列化然後還原序列化