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

【PHP】物件的複製(拷貝)與__clone()方法

Sep 01, 2016 am 12:00 AM

參考連結:

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脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

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

熱門話題

Java教學
1662
14
CakePHP 教程
1419
52
Laravel 教程
1311
25
PHP教程
1262
29
C# 教程
1234
24