自定義__clone()復(fù)制對象
class Person{
public $name;
public function __construct($name) {
$this->name = $name;
}
}
$first = new Person("zhangsan");
$second = $first;
如上例,PHP4時代$second和$first是兩個完全不同的對象,php5之后$second和$first指向同一個對象。但對于基本數(shù)據(jù)類型顯然不是引用復(fù)制。
//PHP 5.2.17 (cli) (built: May 26 2015 16:23:47)
$second->name = "lisi";
var_dump($first === $second); //true
var_dump($second->name); //lisi
var_dump($first->name); //lisi
$third = array(
"hello" => "world",
); //分配數(shù)組的空間0x0001,分配變量$third內(nèi)存,并指向0x0001
$fourth = $third; //分配變量$fourth內(nèi)存,并指向同一地址0x0001,引用計數(shù)加1
var_dump($fourth === $third); //true,內(nèi)容相同,內(nèi)容地址也相同
$fourth['hello'] = "fuck"; //變量改變,重新copy一份出來,給$fourth指向,并修改引用計數(shù)
var_dump($fourth === $third); //false,已經(jīng)是不同的內(nèi)容,不同的地址
這就很尷尬了,雖然引用復(fù)制較為節(jié)省空間,但有時我們希望對象的復(fù)制是值copy,各自保留各自的副本。php提供的clone關(guān)鍵字能夠解決該問題。
$first = new Person("zhangsan");
$second = clone $first; //各自有一份TestPHP的副本
var_dump($first === $second); //false,地址不同
$second->name = "lisi"; //修改的是自己的TestPHP對象內(nèi)容
var_dump($second->name); //lisi
var_dump($first->name); //zhangsan
尷尬的事又出現(xiàn)了,一個clone把事都辦了,那還有啥高級特性?我們?nèi)绻远x對象的copy呢?比如我希望在復(fù)制Person的時候,除id以外的信息,而id要初始化成0。那就需要自定義對象的clone了。
class Person{
public $id;
public $name;
function __construct($id,$name) {
$this->id = $id;
$this->name = $name;
}
public function __clone() {
$this->id = 0;
}
}
$first = new Person("1", "zhangsan");
$second = clone $first;
var_dump($second->id . " | " . $second->name); //0 | zhangsan
var_dump( $first->id . " | " . $first->name ); //1 | zhangsan
這時Account加入了戰(zhàn)斗,問題又出現(xiàn)了。
class Account {
public $balance;
function __construct($balance) {
$this->balance = $balance;
}
}
class Person {
public $id;
public $name;
public $account;
function __construct($id, $name, Account $account) {
$this->id = $id;
$this->name = $name;
$this->account = $account;
}
public function __clone() {
$this->id = 0;
}
}
$first = new Person("1", "zhangsan", new Account(100));
$second = clone $first;
$first->account->balance += 10000;
var_dump($first->account->balance); // 10100
var_dump($second->account->balance); //10100
$first、$second初始化賬戶上應(yīng)該又100元,現(xiàn)在給$first充了10000,結(jié)果$second的賬戶上也被加了10000,,因為在clone Person對象時,account變量的復(fù)制仍然是引用復(fù)制,導(dǎo)致問題,需修改__clone方法
function __clone() {
$this->id = 0;
$this->account = clone $this->account;
}
__autoload()與spl_autoload_register()實現(xiàn)自動加載
PHP5引入了__autoload()攔截器方法實現(xiàn)類文件的自動加載,需要自定義加載函數(shù),其實就是說清楚在php執(zhí)行過程中,遇到未定義的類,到哪兒取找該類的實現(xiàn)文件。
$testLoad = new TestLoad(); //Fatal error: Class 'TestLoad' not found in XXXXX
$testLoad->say();
但是如果自定義實現(xiàn)了__autoload()方法,方法需要傳遞className作為參數(shù)名,然后找到TestLoad類的實現(xiàn),加載類,實例化,調(diào)用say()方法就ok。
function __autoload($className) {
require_once "$className.php"; //自己定義,想加載什么文件、想到哪兒加載文件都是自己定義
}
$testLoad = new TestLoad();
$testLoad->say(); //hello,world
TestLoad類的實現(xiàn)
class TestLoad {
public function say() {
echo "hello,world" . PHP_EOL;
}
}
spl_autoload_register()方法又是干啥的呢? 這么理解,__autoload()方法是正規(guī)軍,系統(tǒng)是認(rèn)識它的,你只要敢定義它,就能實現(xiàn)類的自動加載。但是如果地方軍呢?比如我想起個名字叫XX()的加載函數(shù),就需要使用spl_autoload_register()去登記注冊告訴系統(tǒng)這是自己人,以后遇到未定義類的時候,找XX就行了。
function myLoad($className) {
require_once "$className.php";
}
spl_autoload_register("myLoad");
$testLoad = new TestLoad();
$testLoad->say();