深拷貝和淺拷貝的概念,一般程式設計師都很熟悉,網上的概念解析也很多。可以檢視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));//序列化然後反序列化