魔術(shù)方法是PHP面向?qū)ο笾刑赜械奶匦浴K鼈冊(cè)谔囟ǖ那闆r下被觸發(fā),都是以雙下劃線開頭,你可以把它們理解為鉤子,利用魔術(shù)方法可以輕松實(shí)現(xiàn)PHP面向?qū)ο笾兄剌d(Overloading即動(dòng)態(tài)創(chuàng)建類屬性和方法)。
魔術(shù)方法很多還是成對(duì)出現(xiàn)的,以下列出目前PHP中所有的魔術(shù)方法:
1、__construct()與__destruct
__construct(),類的構(gòu)造函數(shù)。在使用 new關(guān)鍵字使用類實(shí)例化一個(gè)對(duì)象時(shí)自動(dòng)執(zhí)行。
__destruct(),類的析構(gòu)函數(shù)。在對(duì)象被銷毀(unset或PHP執(zhí)行結(jié)束)時(shí)自動(dòng)執(zhí)行,通常用于釋放對(duì)象占用的第三方資源(如:數(shù)據(jù)庫(kù))。
2、__call()與__callStatic()
__call(),在對(duì)象中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用。
class Person{
function __call($funName, $arguments)
{
echo "你所調(diào)用的函數(shù):" . $funName . "不存在。\n\r" ; // 輸出調(diào)用不存在的方法名
echo "參數(shù)為:\n\r";
print_r($arguments); // 輸出調(diào)用不存在的方法時(shí)的參數(shù)列表
}
}
$Person = new Person();
$Person->eat("小明", "蘋果");
以上例程會(huì)輸出:
你所調(diào)用的函數(shù):eat不存在。
參數(shù)為:
Array
(
[0] => 小明
[1] => 蘋果
)
__callStatic(),用靜態(tài)方式中調(diào)用一個(gè)不可訪問方法時(shí)調(diào)用。
public static function __callStatic($funName, $arguments){
//...
}
3、__get()與__set()
當(dāng)對(duì)一個(gè)對(duì)象的未定義的屬性,進(jìn)行“取值”時(shí),此時(shí)會(huì)自動(dòng)調(diào)用類中預(yù)先定義好的魔術(shù)方法__get()。
class Person{
private $name;
private $age;
function __construct($name="", $age=1){
$this->name = $name;
$this->age = $age;
}
public function __get($propertyName){
return $this->$propertyName;
}
}
$Person = new Person("小明", 50);
echo "姓名:" . $Person->name . "\n\r";
echo "年齡:" . $Person->age . "\n\r";
以上例程會(huì)輸出:
姓名:小明
年齡:50
__set(),當(dāng)對(duì)一個(gè)對(duì)象的未定義的屬性,進(jìn)行“賦值”時(shí),此時(shí)會(huì)自動(dòng)調(diào)用類中預(yù)先定義好的魔術(shù)方法__set()。
class Person{
private $name;
private $age;
public function __set($property, $value) {
if ($property=="age"){
if ($value > 150 || $value < 0) {
return;
}
}
$this->$property = $value;
}
}
$Person=new Person();
$Person->name = "小紅"; //賦值成功。如果沒有__set(),則出錯(cuò)。
$Person->age = 16; //賦值成功
$Person->age = 160; //160是一個(gè)非法值,賦值失效
4、__isset()與__unset()
__isset(),當(dāng)對(duì)不可訪問屬性調(diào)用isset()或empty()時(shí)調(diào)用。
__unset(),當(dāng)對(duì)不可訪問屬性調(diào)用unset()時(shí)被調(diào)用。
5、__sleep() 和 __wakeup()
__sleep(),執(zhí)行serialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù);__wakeup(),執(zhí)行unserialize()時(shí),先會(huì)調(diào)用這個(gè)函數(shù)。
__sleep() 方法常用于提交未提交的數(shù)據(jù),或類似的清理操作。同時(shí),如果有一些很大的對(duì)象,但不需要全部保存,這個(gè)功能就很好用。
__wakeup() 經(jīng)常用在反序列化操作中,例如重新建立數(shù)據(jù)庫(kù)連接,或執(zhí)行其它初始化操作。
class Person{
public $sex;
public $name;
public $age;
public function __construct($name="", $age=25, $sex='男'){
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __sleep() {
echo "當(dāng)在類外部使用serialize()時(shí)會(huì)調(diào)用這里的__sleep()方法<br>";
$this->name = base64_encode($this->name);
return array('name', 'age'); // 這里必須返回一個(gè)數(shù)值,里邊的元素表示返回的屬
性名稱
}
public function __wakeup() {
echo "當(dāng)在類外部使用unserialize()時(shí)會(huì)調(diào)用這里的__wakeup()方法<br>";
$this->age = 30;
$this->sex = '女';
// 這里不需要返回?cái)?shù)組
}
}
$person = new Person('小明'); // 初始賦值
$a = serialize($person);
var_dump($a);
$b = unserialize($a);
var_dump($b);
以上例程會(huì)輸出:
當(dāng)在類外部使用serialize()時(shí)會(huì)調(diào)用這里的__sleep()方法
/var/www/html/demo28.php:29:string 'O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}' (length=58)
當(dāng)在類外部使用unserialize()時(shí)會(huì)調(diào)用這里的__wakeup()方法
/var/www/html/demo28.php:31:
object(Person)[2]
public 'sex' => string '女' (length=3)
public 'name' => string '5bCP5piO' (length=8)
public 'age' => int 30
官方例子:
class Connection {
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db) {
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect() {
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}
public function __sleep(){
return array('server', 'username', 'password', 'db');
}
public function __wakeup(){
$this->connect();
}
}
6、__toString()
__toString() 方法用于一個(gè)類被當(dāng)成字符串時(shí)應(yīng)怎樣回應(yīng)。
例如 echo $obj; 應(yīng)該顯示些什么。此方法必須返回一個(gè)字符串,否則將發(fā)出一條 E_RECOVERABLE_ERROR 級(jí)別的致命錯(cuò)誤。
class TestClass{
public $foo = __CLASS__;
public function __toString() {
return $this->foo;
}
}
$class = new TestClass();
echo $class;
以上例程會(huì)輸出:
TestClass
7、__invoke()
當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí),__invoke() 方法會(huì)被自動(dòng)調(diào)用。
class CallableClass {
function __invoke($x) {
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
以上例程會(huì)輸出:
int(5)
bool(true)
8、__set_state()
__set_state(),調(diào)用var_export()導(dǎo)出類時(shí),此靜態(tài)方法會(huì)被調(diào)用。
class A{
public $var1;
public $var2;
public static function __set_state($an_array){
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump($b);
以上例程會(huì)輸出:
object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}
9、__clone()
在克?。╟lone)對(duì)象時(shí)自動(dòng)執(zhí)行。
class C {
public function __clone() {
echo '正在克隆。。。';
}
}
$a = new C();
$b = clone $a;
以上例程會(huì)輸出:
正在克隆。。。
10、__autoload()
__autoload(),嘗試加載未定義的類。
function __autoload($className) {
$filePath = "project/class/{$className}.php";
if (is_readable($filePath)) {
require($filePath);
}
}
隨著PHP版本的更新,該函數(shù)已經(jīng)不建議使用,取而代之的是spl_auto_register()函數(shù)。
11、__debugInfo()
__debugInfo(),打印所需調(diào)試信息。
class C {
private $prop = 'test';
public function __debugInfo() {
return [
'data1' => $this->prop,
];
}
}
var_dump(new C());
以上例程會(huì)輸出:
class C#1 (1) {
public $data1 =>
string(4) "test"
}