重載
PHP中的”重載”與其它絕大多數物件導向語言不同,只是他們都是用的相同的名詞而已。傳統的”重載”是用於提供多個同名的 類方法,但各方法的參數類型和個數不同。 PHP所提供的”重載”(overloading)是指動態地”建立”類屬性和方法。當調用當前環境下未定義或不可見的類屬性或方法時,重載方法會被調用。是通過魔術方法(magic methods)來實現的。
一般來說,把類中的成員屬性都定義為private的,這更符合現實的邏輯,能夠更好的對類中成員起到保護作用。但是,對成員屬性的讀取和賦值操作是非常頻繁的,而如果在類中為每個私人屬性都定義可以在對象的外部擷取和賦值的公有方法,又是非常非常煩惱的。因此在PHP5.1.0以後的版本中,預定義了兩個方法“get()”和“set()”,用來完成對所用私人屬性都能擷取和賦值操作,以及用來檢查私人屬性是否存在的方法“isset()”和用來刪除對象中私人屬性方法“unset()”。
通俗一點來說,重載在php中的含義是指,當一個對象或類使用其未定義或不可見的屬性和方法時,其中的一些“處理機制”。
屬性重載
對一個對象不存在的屬性進行使用時,這個類中預先設定好的應對辦法(處理機制)。
屬性,本質就是變數,其只有4個操作:
取值:
當對一個對象不存在(未定義或不可見)的屬性進行“取值”時,就會自動調用方法:GET() 方法不區分大小寫。
賦值:
當對一個對象不存在(未定義或不可見)的屬性進行“賦值”時,就會自動調用方法:SET()
判斷(isset):
當對一個對象不存在(未定義或不可見)的屬性進行isset()判斷時,就會自動調用方法:isset()
銷毀(unset):
當對一個對象不存在的(未定義或不可見)屬性進行unset()判斷時,就會自動調用方法:unset()
以上4個方法,被稱為魔術方法。
魔術方法
GET($屬性名稱):
在對一個對象不存在的屬性進行“取值”的時候,會自動調用的方法,其中該方法可以帶一個形參,表示要對之取值而又不存在的屬性名稱(字串),可以使用該方法對意外情況進行某種特殊的處理。
例如:
<?phpclass A{ public $p1 = 1;}$a1 = new A();echo $a1->p1; //1echo $a1->p2;//未定義$p2,會報錯, Notice: Undefined property: A::$p2?>
php的重載,使用get()方法對上面的出錯作“優雅處理”。
<?php<?phpclass A{ public $p1 = 1; //private $p2 = 1; //這裡將屬性私人化,其實和未定義一樣,對外部來說都相當於不存在 function get($prop_name){ /* //比如可以這樣處理 echo "<br />{$prop_name}屬性還未定義(不存在)!"; return ""; //也可以返回0,或false等 */ //還可以這樣處理 trigger_error("發生錯誤:屬性不存在!", E_USER_ERROR); die(); }}$a1 = new A();echo $a1->p1; //1echo $a1->p2;//未定義$p2,但經過"處理"?>
這裡舉一個對所用私人屬性擷取的操作的例子。
例子:
<?phpclass Person{ public $name; public $sex; private $age; //年齡私人化,類外不能直接存取這個屬性 function construct($name='', $sex='', $age){ $this->name = $name; $this->sex = $sex; $this->age = $age; } private function get($propertyName){ //這裡要用private修飾,防止類外部調用 if($propertyName == 'age'){ return $this->age; } }}$p = new Person('yeoman', '男',23);$v1 = $p->name;$v2 = $p->sex;$v3 = $p->age; //自動調用了get()方法擷取私人屬性age(函數定義裡面返回)echo "name=$v1, sex=$v2, age=$v3";?>
運行結果為:
name=yeoman, sex=男, age=23
SET($屬性名稱, 值):
當對一個對象不存在的屬性進行“賦值”時,就會自動調用這個內部的魔術方法;其有2個形參,分別代表要對不存在的屬性進行賦值的“屬性名稱”和“屬性值”。
這個方法,結合_GET方法,往往可以使我們定義的類,有一種可擴充的特性。即:類或對象的屬性,可以更為方便自由。
例子:
<?phpclass A{ //定義一個屬性, protected $prop_list = array(); //初始為空白數組 //這個方法會在A的對象使用一個不存在的屬性進行賦值時調用 function set($p,$v){ //echo "使用不存在的屬性!"; $this->prop_list[$p] = $v; } function get($p){ return $this->prop_list[$p]; }}$a1 = new A();$a1->p1 = 1; //不存在的屬性名稱賦值,此時會調用_set(),並傳過去"p1"和1$a1->p2 = 2;$a1->ac = 'avc';echo "<br />輸出這些“不存在的屬性”的值:";echo "<br />a1->p1:" . $a1->p1; //不存在的屬性名稱取值,此時會調用_get(),並傳過去"p1"echo "<br />a1->p2:" . $a1->p2;echo "<br />a1->ac:" . $a1->ac;?>
運行結果為:
輸出這些“不存在的屬性”的值:a1->p1:1a1->p2:2a1->ac:avc
ISSET($屬性名稱):
當對一個對象不存在的屬性進行isset()判斷時,就會自動調用內部方法:isset();
用法:
$v1 = isset($對象->不存在的屬性); //此時會調用這個對象所屬類中的魔術方法:isset()
例子:
<?phpclass A{ //定義一個屬性, protected $prop_list = array(); //初始為空白數組 //這個方法會在A的對象使用一個不存在的屬性進行賦值時調用 function set($p,$v){ //echo "使用不存在的屬性!"; $this->prop_list[$p] = $v; } function get($p){ if($this->prop_list[$p]){ return $this->prop_list[$p]; }else{ return "該屬性不存在!"; } } function isset($prop){ //isset()是自訂的方法, isset()是系統函數 $re = isset($this->prop_list[$prop]); return $re; }}$a1 = new A();$a1->p1 = 1;//不存在的屬性名稱賦值,此時會調用_set(),並傳過去"p1"和1$a1->p2 = 2;$a1->ac = 'avc';echo "<br />輸出這些“不存在的屬性”的值";echo "<br />a1->p1:" . $a1->p1;//不存在的屬性名稱取值,此時會調用_get(),並傳過去"p1"echo "<br />a1->p2:" . $a1->p2;echo "<br />a1->ac:" . $a1->ac;//下面示範isset判斷不存在的屬性$v1 = isset($a1->p1); //存在$v2 = isset($a1->ppp1); //不存在var_dump($v1);echo "<br />";var_dump($v2);?>
運行結果:
輸出這些“不存在的屬性”的值a1->p1:1a1->p2:2a1->ac:avcboolean trueboolean false
UNSET($屬性名稱)
當對一個對象不存在的屬性進行unset()銷毀時,就會自動調用內部方法:unset();
<?phpclass A{ //定義一個屬性, protected $prop_list = array(); //初始為空白數組 //這個方法會在A的對象使用一個不存在的屬性進行賦值時調用 function set($p,$v){ //echo "使用不存在的屬性!"; $this->prop_list[$p] = $v; } function get($p){ if($this->prop_list[$p]){ return $this->prop_list[$p]; }else{ return "該屬性不存在!"; } } function unset($prop){ unset($this->prop_list[$prop]); }}$a1 = new A();$a1->p1 = 1;//不存在的屬性名稱賦值,此時會調用_set(),並傳過去"p1"和1echo "<br />a1->p1:" . $a1->p1;//不存在的屬性名稱取值,此時會調用_get(),並傳過去"p1"//下面示範unset銷毀一個不存在的屬性unset($a1->p1);echo "<br />a1->p1:" . $a1->p1;?>
運行結果為:
a1->p1:1a1->p1:該屬性不存在!
下面的例子中,聲明一個Person類,並將所有的成員屬性設定成private的。在類中添加自訂的“isset()”和“unset()”兩個方法。在類外部使用“isset()”和“unset()”函數時,會自動調用這兩個方法。代碼如下:
<?phpclass Person{ private $name; //此屬性被封住 private $sex; private $age; function __construct($name='', $sex='男', $age){ $this->name = $name; $this->sex = $sex; $this->age = $age; } private function __isset($propertyName){ //需要一個參數,是測定的私人屬性的名稱 if($propertyName == 'name'){ return false; //返回假,不允許在類外部測定name屬性 } return isset($this->$propertyName); //這裡propertyName要加$符,因為這是參數,不是屬性 } private function __unset($propertyName){ if($propertyName == 'name') return; //退出方法,不允許刪除對象中的name屬性 unset($this->$propertyName); //這裡propertyName要加$符 } public function say(){ echo "名字:" . $this->name . ",性別:" . $this->sex . ",年齡:" . $this->age . "<br />"; }}$person = new Person("yeoman", "男", 23);var_dump(isset($person->name)); //輸出bool(false),不允許測定name屬性var_dump(isset($person->sex)); //輸出bool(true),存在sex私人屬性var_dump(isset($person->age)); //輸出bool(true),存在age私人屬性var_dump(isset($person->id)); //輸出bool(false),測定對象中不存在id屬性unset($person->name); //刪除私人屬性name,但在 __unset()中不允許刪除unset($person->sex); //刪除對象中的私人屬性sex,刪除成功unset($person->age);$person->say(); //對象中的sex和age屬性被刪除,輸出:名字:yeoman,性別:,年齡:?>
運行結果:
boolean falseboolean trueboolean trueboolean false名字:yeoman,性別:,年齡:
方法重載
當對一個對象不存在的執行個體方法進行“調用”時,會自動調用類中的call()這個魔術方法;
當對一個類不存在的靜態方法進行“調用”時,會自動調用類中的callstatic()這個魔術方法。
例子:直接調用不存在的方法
<?phpini_set('display_errors',1);class A{}$a = new A();$a->f1(); //不存在的方法?>
會報錯,報錯內容為:
Fatal error: Uncaught Error: Call to undefined method A::f1()
對上面報錯作“優雅處理”:
<?phpclass A{ //當對這個類的對象不存在的實力方法進行調用時,會自動調用本方法 //這個方法必須帶2個形參: //$methodName:表示要調用的不存在的方法名; //$argument:表示要調用該不存在的方法時,所使用的實參資料,是一個數組。 function call($methodName, $argument){ //echo "call被調用了!"; echo $methodName . "()方法不存在!"; }}$a = new A();$a->f1(); //不存在的方法,但經過處理?>
運行結果為:
f1()方法不存在!
當對一個類不存在的靜態方法進行“調用”時,會自動調用類中的callstatic()這個魔術方法。和上面的處理類似。