搜尋
首頁php教程php手册【PHP】物件的複製(拷貝)與__clone()方法

參考連結:

1、php.net官網文件 - 物件複製

 

什麼時候用到?摘自php.net:

在多數情況下,我們並不需要完全複製一個物件來獲得其中屬性。但有一個情況下確實需要:如果你有一個 GTK 視窗對象,該對象持有視窗相關的資源。你可能會想複製一個新的窗口,保持所有屬性與原來的窗口相同,但必須是一個新的對象(因為如果不是新的對象,那麼一個窗口中的改變就會影響到另一個窗口)。還有一種情況:如果物件A 中保存著物件B 的引用,當你複製物件A 時,你想其中使用的物件不再是物件B 而是B 的一個副本,那麼你必須得到物件A 的副本。

 

嘗試使用最簡單的「=」

首先要明確的是:php的物件是以一個標識符來儲存的,所以對物件的直接「賦值」行為相當於「傳引用」

<?php

function dump($var){
    var_dump($var);
    echo "<br/>";
}

class A{
    private $a;
    protected $b;
    public $c;

    public function d(){
        echo "A -> d";
    }
}

$a1 = new A();
$a2 = $a1;
$a3 = new A();
dump($a1);
dump($a2);
dump($a3);

 

輸出的結果是:

object(A)#1 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL } 
object(A)#1 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL } 
object(A)#2 (3) { ["a":"A":private]=> NULL ["b":protected]=> NULL ["c"]=> NULL } 

其中可以注意到,作為對象標識符的#n,顯示$a1和$a2其實是指向同一個對象,而$a3是另一個對象

所以,如果需要拷貝一個相同且全新的對象,不能直接通過=來複製,否則改變了$a1->a就相當於修改了$a2->a。

 

淺拷貝

PHP5中,類別中有個魔術方法__clone(),在配合clone關鍵字和物件使用的時候,會自動呼叫(如果沒有明確定義,則呼叫空的方法)。

clone關鍵字的作用是,複製某一個對象形成一個對象的“淺拷貝”,然後賦值給新的對象,此時對象標識符不同了!

<?php

function dump($var){
    var_dump($var);
    echo "<br/>";
}

class B{
    public $d;
}

class A{
    public $a;
    public $b;

    public function d(){
        echo "A -> d";
    }
}

$a1 = new A();
$a1->a = 123;
// 这里对象属性的值是一个对象示例,其实就是存储了对象标识符。使用clone关键字生成的拷贝中的b属性仍然指向旧对象的b属性指向的对象,这是"浅拷贝"出现的问题。如果需要指向一个新的对象,必须"深拷贝"
$a1->b = new B();

// PHP 5 only
$a2 = clone $a1;

dump($a1);
dump($a2);

 

輸出的結果是:

object(A)#1 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } } 
object(A)#3 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } } 

可以看到,$a1和$a2明顯是兩個不同的物件(物件識別碼不同了)。但需要留意的一點是,"b"指向的物件識別碼都是#2,證明這兩個物件是相同的,這就是「淺拷貝」的「缺陷」——但有時這兩個物件確實需要相同,所以PHP的clone預設是「淺拷貝」。

 

為什麼叫淺拷貝(shallow copy)?

因為在複製的時候,所有的屬性都是“值傳遞”的,而上面的b屬性存儲的是對象標識符,所以相當於做了“引用傳遞”,這並不是完全的拷貝,所以稱為「淺拷貝」。

 

深拷貝

上面講到,使用clone關鍵字的時候,會自動呼叫舊物件的__clone()方法(然後傳回拷貝的物件),所以只需要在對應的類別中重寫__clone()方法,使返回的物件中的「引用傳遞」的屬性指向另一個新的物件。以下是例子(可以比較「淺拷貝」的例子,其實多了重寫__clone()的步驟):

<?php

function dump($var){
    var_dump($var);
    echo "<br/>";
}

class B{
    public $d;
}

class A{
    public $a;
    public $b;

    public function d(){
        echo "A -> d";
    }

    public function __clone(){
        // clone自己
        $this->b = clone $this->b;
    }
}

$a1 = new A();
$a1->a = 123;
// 这里对象属性的值是一个对象示例,其实就是存储了对象标识符。使用clone关键字生成的拷贝中的b属性仍然指向旧对象的b属性指向的对象,这是"浅拷贝"出现的问题。如果需要指向一个新的对象,必须"深拷贝"
$a1->b = new B();

// PHP 5 only
$a2 = clone $a1;

dump($a1);
dump($a2);

 

結果就不同了,注意b​​屬性的物件識別碼:

object(A)#1 (2) { ["a"]=> int(123) ["b"]=> object(B)#2 (1) { ["d"]=> NULL } } 
object(A)#3 (2) { ["a"]=> int(123) ["b"]=> object(B)#4 (1) { ["d"]=> NULL } } 

 

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)