在面向對象的編程中,PHP為我們提供很多魔術方法,靈活的使用這些魔術方法,可以簡化我們在面向對象開發過程中的很多操作。在PHP中,魔術方法通常都是以兩個下劃線(__)開頭的。與PHP中的普通方法(方法也稱函數)不同的是,魔術方法通常是在特定情況下由程序自動調用的,而普通方法通常是由我們手動調用的。魔術方法為我們提供了非常有用的功能,PHP中的魔術方法有很多,具體有哪些,大家可以參考下PHP的手冊,在這裡即可查看。在本篇文章中,我僅僅為大家簡單介紹下一些常用的魔術方法。
一、准備工作
為了充分理解魔術方法的概念,我們就需要在代碼中使用下這些魔術方法,只有概念性的東西,估計看過一遍也就忘了。所以這裡我們需要先定義兩個簡單的類。
通常,我們習慣將每個類都定義在一個單獨的文件中,類文件以”類名.class.php”的形式命名。這裡我們定義兩個簡單的類一個是Device類,一個是Battery類。定義的兩個類如下所示:
文件:Device.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Device{
public $name;
public $battery;
public $data=array();
public $connection;
protected function connect(){
$this->connection='resource';
echo $this->name.'connected'.PHP_EOL;
}
protected function disconnect(){
$this->connection=null;
echo $this->name.'disconnected'.PHP_EOL;
}
}
?>
文件:Battery.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class Battery{
private $charge=0;
public function setCharge($charge){
$charge=(int)$charge;
if($charge<0){
$charge=0;
}else{
$charge=100;
}
$this->charge=$charge;
}
}
?>
在Device類中,定義了四個成員屬性,分別是:name用來表示設備的名稱,battery用來保存一個Battery對象,data被定義為數組,connection用來保存外外部資源的句柄。在該類中,同樣定義了兩個成員方法connect()和disconnect()分別用來建立和斷開連接。
在Battery類中,僅僅定義了一個私有屬性charge和一個成員方法setCharge()用來設置charge的值。
這裡定義的兩個類,並沒有什麼實際的用途,僅僅是為了使大家能夠更好的理解PHP中的魔術方法。
二、構造函數和析構函數
構造函數和析構函數是在對象被創建和銷毀時,由系統自動調用的。
1.構造函數:__construct()
__construct函數是目前為止被使用最多的魔術函數。當對象被創建的時候,我們可以在構造函數中進行任何的初始化操作,特別是對成員變量進行初始化操 作。可以為構造函數定義任意數量的參數。無論構造函數出於何種原因不能被正確執行,那麼對象的創建就會失敗。下面是在Device類中使用構造函數的例子。
1
2
3
4
5
6
public function __construct($name,Battery $battery){
//battery的值只能是由Battery類實例化的一個對象
$this->battery=$battery;
$this->name=$name;
$this->connect();
}
在這個構造函數中,我們為構造函數指定了兩個形參,分別為成員屬性name和battery賦值,同時在構造函數中還調用了該類的connect()函數。
注意:將構造函數聲明為私有方法可以阻止程序在類外部直接創建該類的一個實例對象,這在實現設計模式的單例模式時很常用。
有了構造函數,我們可以像下面的代碼一樣實例化一個Device類的對象。
1
$device=new Device('iPhone',$battery);
2.析構函數:__destruct()
與構造函數相反,析構函數是在對象被銷毀時由系統自動調用的。在類中定義構造函數的方式如下:
1
2
3
public function __destruct(){
$this->disconnect();
}
在這個析構函數中,在對象被銷毀之前,析構器先調用了類中的disconnect()函數。
三、屬性重載
根據PHP手冊中的說明,PHP所提供的”重載”(overloading)是指動態地”創建”類屬性和方法。我們是通過魔術方法(magic methods)來實現的。
當調用當前環境下未定義或不可見的類屬性或方法時,重載方法會被調用,換句話說,當訪問一個類中可訪問的方法或屬性時,重載方法不會被調用。所有的重載方法都必須被聲明為 public。
1.__get()
當讀取不可訪問屬性的值時,__get() 會被調用。
2.__set()
在給不可訪問屬性賦值時,__set() 會被調用。
3.__isset()
當對不可訪問屬性調用 isset() 或 empty() 時,__isset() 會被調用。
4.__unset()
當對不可訪問屬性調用 unset() 時,__unset() 會被調用。
四、將對象轉換為字符串:__toString()
在我們試圖將對象當做一個普通字符串來對待時,__toString方法會被調用。比如,當我們打印一個對象時,就會自動調用該函數,如:echo $對象名,如果沒有定義__toString方法,那麼PHP將返回一個錯誤。
五、克隆對象:__clone()
當我們克隆一個對象時,魔術方法__clone()會被自動調用
六、對象序列化
序列化是將任何數據轉化為字符串格式的一個過程。通過序列化,我們可以將一個完整的對象保存在一個文件或者保存在數據庫中。有關序列化的一個問題是,並不是所有的數據都可以被序列化,例如一個數據庫連接。
1.__sleep()
當我們對一個對象使用serialize()函數時,__sleep()函數會被調用。
2.__wakeup()
當我們對一個對象使用unserialize()函數時,__wakeup()函數會被調用。
七、方法重載
1.__call()
在對象中調用一個不可訪問方法時,__call() 會被調用。
2.__callStatic() (PHP 5.3)
用靜態方式中調用一個不可訪問方法時,__callStatic() 會被調用。
八、將對象當作函數使用
1.__invoke
當我們試圖將對象當做函數來使用時,該方法會被調用。
九、自動加載類
1.__autoload()
該方法是我們在實例化一個類時,允許程序自動尋找類文件,並將類文件加載到當前腳本,可以簡化很多我們對require的使用。