PHP對象的克隆與引用有什么區別?


是這樣的,這個問題確切說應該是這樣的:“ PHP對象的賦值和克隆有什么區別 ”,注意不是復制,就是復制,打開窗子說亮話,就是下面兩行有什么區別。

class User{
  public $username = 'test';
}
$user1 = new User();
// 注意下面兩行,有啥子區別
$user2 = $user1;
$user2 = clone $user1;

$user2 = $user1這種寫法,實際上是引用寫法,也就是說本質上user1和user2變量指向的都是同一個PHP對象,占用的內存也只有一份,如果你修改user2的username屬性實際上就是在user1的username屬性,當然了,修改user1的username屬性也是在修改user2的username屬性,搞來搞去都是同一個。

然而,$user2 = clone $user1這種寫法表示實打實地復制一個User對象出來,而不是普普通通的引用了,這種情況下,你修改user2的username屬性不會影響user1的username屬性,修改user1的任何屬性也不會影響到user2的屬性,說到底是占用了兩份內存。但是,要值得注意的是,你執行完畢clone后系統也並不會真的立馬就開辟一塊兒新的內存用於存放新的對象。如果你clone完這個對象后,並沒有修改、添加、刪除任何屬性或者方法,這兩個對象在內存依然為同一個,只有在你對任意一個對象的屬性或者方法進行增刪改的時候,系統才會真的再開辟一塊兒內存復制對象,這種技術叫做寫實拷貝,是節約內容的一大利器!很多地方都會利用這種技術,大家要記住。

php中有個魔術方法叫做__clone,這個方法呢,只有在你執行clone的時候,會被自動觸發,如果你要對某個類在被克隆的時候做一些特殊操作,那么你就可以在這個類中自定義一些業務邏輯進來,這個具體就要看你的業務場景了。注意,如果你在__clone魔術方法中直接修改類的屬性,他修改的是新復制出來的類的屬性,而不是老類的屬性,用上面的例子就是會修改user2的屬性,而不是user1的屬性,具體代碼如下:

<?php
class User{
  public $username = 'test';
  public function __clone() {
    $this->username = 'www';
  }
}
$user1 = new User();
// 注意下面兩行,有啥子區別
$user2 = $user1;
$user2 = clone $user1;

__clone方法中修改username屬性為www,修改的是user2對象,而不是user1!

$user2 = $user1,就是傳說中的淺復制。
$user2 = clone $user1,就是傳說中的深復制。

然而,深復制依然有特例,比如下面這坨代碼:

<?php
class People {
  public $age = 18;
}
class User {
  public $username = 'zhangsan';
  public $peple = null;
  public function __construct() {
    $this->people = new People();
  }
}
$user1 = new User();
$user2 = clone $user1;
$user1->username = 'lisi';
$user1->people->age = 22;
echo $user1->username.PHP_EOL;
echo $user1->people->age.PHP_EOL;
echo $user2->username.PHP_EOL;
echo $user2->people->age.PHP_EOL;

結果是啥,你們自己可以運行一下,我只說結果,反正就是user1和user2的username屬性確實是不受影響了,但是people屬性卻是指向的同一個,這個十分尷尬,也就說即便是深復制,當類的某個屬性為另外一個對象的時候,默認只會淺復制這個對象屬性,那么如何徹底地復制對象類型的屬性呢?還得靠__clone魔術方法...

<?php
class People {
  public $age = 18;
}
class User {
  public $username = 'zhangsan';
  public $peple = null;
  public function __construct() {
    $this->people = new People();
  }
  public function __clone() {
    $this->people = new People();
  }
}
$user1 = new User();
$user2 = clone $user1;
$user1->username = 'lisi';
$user1->people->age = 22;
echo $user1->username.PHP_EOL;
echo $user1->people->age.PHP_EOL;
echo $user2->username.PHP_EOL;
echo $user2->people->age.PHP_EOL;

運行一下,感受一下結果。

那么,對象的克隆有什么用處呢?

舉個例子吧,比如某個控制器方法中,你通過查詢數據庫返回了一個數據對象為$user,然后你直接echo json_encode( $user )給客戶端,但是在輸出之前呢,你還需要對這個$user進行一些業務邏輯運算,比如對某個屬性加1,然后存入到redis中,但是客戶端又需要的是最原始的從數據庫取出的狀態,那么這個時候,你就只能clone一下這個對象,原對象用於輸出給客戶端,另外一個備份對象用於redis存儲。

在我們公司,也遇到大量的clone,都是用於構建請求對象,和上面這種應用場景是非常類似的,構建出一個原始對象,用於形成最終數據給客戶端,同時克隆一個這個原始對象用於邏輯業務處理生成另外一個結果。

 

轉:https://t.ti-node.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM