PHP面向?qū)ο蟪绦蛟O(shè)計(jì)重載(overloading)操作詳解
本文實(shí)例講述了PHP面向?qū)ο蟪绦蛟O(shè)計(jì)重載(overloading)操作。分享給大家供大家參考,具體如下:
重載
PHP中的”重載”與其它絕大多數(shù)面向?qū)ο笳Z言不同,只是他們都是用的相同的名詞而已。傳統(tǒng)的”重載”是用于提供多個(gè)同名的 類方法,但各方法的參數(shù)類型和個(gè)數(shù)不同。 PHP所提供的”重載”(overloading)是指動(dòng)態(tài)地”創(chuàng)建”類屬性和方法。當(dāng)調(diào)用當(dāng)前環(huán)境下未定義或不可見的類屬性或方法時(shí),重載方法會(huì)被調(diào)用。是通過魔術(shù)方法(magic methods)來實(shí)現(xiàn)的。
一般來說,把類中的成員屬性都定義為private的,這更符合現(xiàn)實(shí)的邏輯,能夠更好的對(duì)類中成員起到保護(hù)作用。但是,對(duì)成員屬性的讀取和賦值操作是非常頻繁的,而如果在類中為每個(gè)私有屬性都定義可以在對(duì)象的外部獲取和賦值的公有方法,又是非常非常煩惱的。因此在PHP5.1.0以后的版本中,預(yù)定義了兩個(gè)方法“__get()”和“__set()”,用來完成對(duì)所用私有屬性都能獲取和賦值操作,以及用來檢查私有屬性是否存在的方法“__isset()”和用來刪除對(duì)象中私有屬性方法“__unset()”。
通俗一點(diǎn)來說,重載在php中的含義是指,當(dāng)一個(gè)對(duì)象或類使用其未定義或不可見的屬性和方法時(shí),其中的一些“處理機(jī)制”。
屬性重載
對(duì)一個(gè)對(duì)象不存在的屬性進(jìn)行使用時(shí),這個(gè)類中預(yù)先設(shè)定好的應(yīng)對(duì)辦法(處理機(jī)制)。
屬性,本質(zhì)就是變量,其只有4個(gè)操作:
取值:
當(dāng)對(duì)一個(gè)對(duì)象不存在(未定義或不可見)的屬性進(jìn)行“取值”時(shí),就會(huì)自動(dòng)調(diào)用方法:__GET()
方法不區(qū)分大小寫。
賦值:
當(dāng)對(duì)一個(gè)對(duì)象不存在(未定義或不可見)的屬性進(jìn)行“賦值”時(shí),就會(huì)自動(dòng)調(diào)用方法:__SET()
判斷(isset):
當(dāng)對(duì)一個(gè)對(duì)象不存在(未定義或不可見)的屬性進(jìn)行isset()判斷時(shí),就會(huì)自動(dòng)調(diào)用方法:isset()
銷毀(unset):
當(dāng)對(duì)一個(gè)對(duì)象不存在的(未定義或不可見)屬性進(jìn)行unset()判斷時(shí),就會(huì)自動(dòng)調(diào)用方法:unset()
以上4個(gè)方法,被稱為魔術(shù)方法。
魔術(shù)方法
__GET($屬性名):
在對(duì)一個(gè)對(duì)象不存在的屬性進(jìn)行“取值”的時(shí)候,會(huì)自動(dòng)調(diào)用的方法,其中該方法可以帶一個(gè)形參,表示要對(duì)之取值而又不存在的屬性名(字符串),可以使用該方法對(duì)意外情況進(jìn)行某種特殊的處理。
例如:
<?php class A{ public $p1 = 1; } $a1 = new A(); echo $a1->p1; //1 echo $a1->p2; //未定義$p2,會(huì)報(bào)錯(cuò), Notice: Undefined property: A::$p2 ?>
php的重載,使用__get()
方法對(duì)上面的出錯(cuò)作“優(yōu)雅處理”。
<?php class A{ public $p1 = 1; //private $p2 = 1; //這里將屬性私有化,其實(shí)和未定義一樣,對(duì)外部來說都相當(dāng)于不存在 function __get($prop_name){ /* //比如可以這樣處理 echo "<br />{$prop_name}屬性還未定義(不存在)!"; return ""; //也可以返回0,或false等 */ //還可以這樣處理 trigger_error("發(fā)生錯(cuò)誤:屬性不存在!", E_USER_ERROR); die(); } } $a1 = new A(); echo $a1->p1; //1 echo $a1->p2; //未定義$p2,但經(jīng)過"處理" ?>
這里舉一個(gè)對(duì)所用私有屬性獲取的操作的例子。
例子:
<?php class Person{ public $name; public $sex; private $age; //年齡私有化,類外不能直接訪問這個(gè)屬性 function __construct($name='', $sex='', $age){ $this->name = $name; $this->sex = $sex; $this->age = $age; } private function __get($propertyName){ //這里要用private修飾,防止類外部調(diào)用 if($propertyName == 'age'){ return $this->age; } } } $p = new Person('yeoman', '男',23); $v1 = $p->name; $v2 = $p->sex; $v3 = $p->age; //自動(dòng)調(diào)用了__get()方法獲取私有屬性age(函數(shù)定義里面返回) echo "name=$v1, sex=$v2, age=$v3"; ?>
運(yùn)行結(jié)果為:
name=yeoman, sex=男, age=23
__SET($屬性名, 值):
當(dāng)對(duì)一個(gè)對(duì)象不存在的屬性進(jìn)行“賦值”時(shí),就會(huì)自動(dòng)調(diào)用這個(gè)內(nèi)部的魔術(shù)方法;其有2個(gè)形參,分別代表要對(duì)不存在的屬性進(jìn)行賦值的“屬性名”和“屬性值”。
這個(gè)方法,結(jié)合_GET方法,往往可以使我們定義的類,有一種可擴(kuò)展的特性。即:類或?qū)ο蟮膶傩?,可以更為方便自由?/p>
例子:
<?php class A{ //定義一個(gè)屬性, protected $prop_list = array(); //初始為空數(shù)組 //這個(gè)方法會(huì)在A的對(duì)象使用一個(gè)不存在的屬性進(jìn)行賦值時(shí)調(diào)用 function __set($p,$v){ //echo "使用不存在的屬性!"; $this->prop_list[$p] = $v; } function __get($p){ return $this->prop_list[$p]; } } $a1 = new A(); $a1->p1 = 1; //不存在的屬性名賦值,此時(shí)會(huì)調(diào)用_set(),并傳過去"p1"和1 $a1->p2 = 2; $a1->ac = 'avc'; echo "<br />輸出這些“不存在的屬性”的值:"; echo "<br />a1->p1:" . $a1->p1; //不存在的屬性名取值,此時(shí)會(huì)調(diào)用_get(),并傳過去"p1" echo "<br />a1->p2:" . $a1->p2; echo "<br />a1->ac:" . $a1->ac; ?>
運(yùn)行結(jié)果為:
輸出這些“不存在的屬性”的值:
a1->p1:1
a1->p2:2
a1->ac:avc
__ISSET($屬性名):
當(dāng)對(duì)一個(gè)對(duì)象不存在的屬性進(jìn)行isset()
判斷時(shí),就會(huì)自動(dòng)調(diào)用內(nèi)部方法:isset()
;
用法:
$v1 = isset($對(duì)象->不存在的屬性); //此時(shí)會(huì)調(diào)用這個(gè)對(duì)象所屬類中的魔術(shù)方法:isset()
例子:
<?php class A{ //定義一個(gè)屬性, protected $prop_list = array(); //初始為空數(shù)組 //這個(gè)方法會(huì)在A的對(duì)象使用一個(gè)不存在的屬性進(jìn)行賦值時(shí)調(diào)用 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()是系統(tǒng)函數(shù) $re = isset($this->prop_list[$prop]); return $re; } } $a1 = new A(); $a1->p1 = 1;//不存在的屬性名賦值,此時(shí)會(huì)調(diào)用_set(),并傳過去"p1"和1 $a1->p2 = 2; $a1->ac = 'avc'; echo "<br />輸出這些“不存在的屬性”的值"; echo "<br />a1->p1:" . $a1->p1;//不存在的屬性名取值,此時(shí)會(huì)調(diào)用_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); ?>
運(yùn)行結(jié)果:
輸出這些“不存在的屬性”的值
a1->p1:1
a1->p2:2
a1->ac:avc
boolean true
boolean false
__UNSET($屬性名)
當(dāng)對(duì)一個(gè)對(duì)象不存在的屬性進(jìn)行unset()
銷毀時(shí),就會(huì)自動(dòng)調(diào)用內(nèi)部方法:unset()
;
<?php class A{ //定義一個(gè)屬性, protected $prop_list = array(); //初始為空數(shù)組 //這個(gè)方法會(huì)在A的對(duì)象使用一個(gè)不存在的屬性進(jìn)行賦值時(shí)調(diào)用 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;//不存在的屬性名賦值,此時(shí)會(huì)調(diào)用_set(),并傳過去"p1"和1 echo "<br />a1->p1:" . $a1->p1;//不存在的屬性名取值,此時(shí)會(huì)調(diào)用_get(),并傳過去"p1" //下面演示unset銷毀一個(gè)不存在的屬性 unset($a1->p1); echo "<br />a1->p1:" . $a1->p1; ?>
運(yùn)行結(jié)果為:
a1->p1:1
a1->p1:該屬性不存在!
下面的例子中,聲明一個(gè)Person類,并將所有的成員屬性設(shè)置成private的。在類中添加自定義的“__isset()
”和“__unset()
”兩個(gè)方法。在類外部使用“isset()
”和“unset()
”函數(shù)時(shí),會(huì)自動(dòng)調(diào)用這兩個(gè)方法。代碼如下:
<?php class 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){ //需要一個(gè)參數(shù),是測(cè)定的私有屬性的名稱 if($propertyName == 'name'){ return false; //返回假,不允許在類外部測(cè)定name屬性 } return isset($this->$propertyName); //這里propertyName要加$符,因?yàn)檫@是參數(shù),不是屬性 } private function __unset($propertyName){ if($propertyName == 'name') return; //退出方法,不允許刪除對(duì)象中的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),不允許測(cè)定name屬性 var_dump(isset($person->sex)); //輸出bool(true),存在sex私有屬性 var_dump(isset($person->age)); //輸出bool(true),存在age私有屬性 var_dump(isset($person->id)); //輸出bool(false),測(cè)定對(duì)象中不存在id屬性 unset($person->name); //刪除私有屬性name,但在 __unset()中不允許刪除 unset($person->sex); //刪除對(duì)象中的私有屬性sex,刪除成功 unset($person->age); $person->say(); //對(duì)象中的sex和age屬性被刪除,輸出:名字:yeoman,性別:,年齡: ?>
運(yùn)行結(jié)果:
boolean false
boolean true
boolean true
boolean false
名字:yeoman,性別:,年齡:
方法重載
當(dāng)對(duì)一個(gè)對(duì)象不存在的實(shí)例方法進(jìn)行“調(diào)用”時(shí),會(huì)自動(dòng)調(diào)用類中的__call()
這個(gè)魔術(shù)方法;
當(dāng)對(duì)一個(gè)類不存在的靜態(tài)方法進(jìn)行“調(diào)用”時(shí),會(huì)自動(dòng)調(diào)用類中的__callstatic()
這個(gè)魔術(shù)方法。
例子:直接調(diào)用不存在的方法
<?php ini_set('display_errors',1); class A{ } $a = new A(); $a->f1(); //不存在的方法 ?>
會(huì)報(bào)錯(cuò),報(bào)錯(cuò)內(nèi)容為:
Fatal error: Uncaught Error: Call to undefined method A::f1()
對(duì)上面報(bào)錯(cuò)作“優(yōu)雅處理”:
<?php class A{ //當(dāng)對(duì)這個(gè)類的對(duì)象不存在的實(shí)力方法進(jìn)行調(diào)用時(shí),會(huì)自動(dòng)調(diào)用本方法 //這個(gè)方法必須帶2個(gè)形參: //$methodName:表示要調(diào)用的不存在的方法名; //$argument:表示要調(diào)用該不存在的方法時(shí),所使用的實(shí)參數(shù)據(jù),是一個(gè)數(shù)組。 function __call($methodName, $argument){ //echo "__call被調(diào)用了!"; echo $methodName . "()方法不存在!"; } } $a = new A(); $a->f1(); //不存在的方法,但經(jīng)過處理 ?>
運(yùn)行結(jié)果為:
f1()方法不存在!
當(dāng)對(duì)一個(gè)類不存在的靜態(tài)方法進(jìn)行“調(diào)用”時(shí),會(huì)自動(dòng)調(diào)用類中的__callstatic()
這個(gè)魔術(shù)方法。和上面的處理類似。
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《PHP數(shù)組(Array)操作技巧大全》、《PHP基本語法入門教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
相關(guān)文章
解析mysql中UNIX_TIMESTAMP()函數(shù)與php中time()函數(shù)的區(qū)別
本篇文章是對(duì)mysql中UNIX_TIMESTAMP()函數(shù)與php中time()函數(shù)的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP系列學(xué)習(xí)之日期函數(shù)使用介紹
PHP有非常豐富的庫資源,便于開發(fā)者很容易的處理一些業(yè)務(wù)。由于我們?cè)陧?xiàng)目中與日期接觸最多,所以今天就從日期函數(shù)入手學(xué)習(xí)2012-08-08PHP定時(shí)自動(dòng)生成靜態(tài)HTML的實(shí)現(xiàn)代碼
為了提高網(wǎng)站的訪問速度,我們往往采用生成靜態(tài)的方式來實(shí)現(xiàn),這樣確實(shí)把網(wǎng)站的訪問速度提高了非常多.2010-06-06圖文詳解phpstorm配置Xdebug進(jìn)行調(diào)試PHP教程
這篇文章主要為大家詳細(xì)的介紹了phpstorm配置Xdebug進(jìn)行調(diào)試PHP教程 ,感興趣的小伙伴們可以參考一下2016-06-06