php5.3后靜態(tài)綁定用法詳解
本文實(shí)例講述了php5.3后靜態(tài)綁定用法。分享給大家供大家參考,具體如下:
手冊(cè)原文:
自 PHP 5.3.0 起,PHP 增加了一個(gè)叫做后期靜態(tài)綁定的功能,用于在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。
準(zhǔn)確說(shuō),后期靜態(tài)綁定工作原理是存儲(chǔ)了在上一個(gè)"非轉(zhuǎn)發(fā)調(diào)用"(non-forwarding call)的類名。當(dāng)進(jìn)行靜態(tài)方法調(diào)用時(shí),該類名即為明確指定的那個(gè)(通常在 :: 運(yùn)算符左側(cè)部分);當(dāng)進(jìn)行非靜態(tài)方法調(diào)用時(shí),即為該對(duì)象所屬的類。所謂的"轉(zhuǎn)發(fā)調(diào)用"(forwarding call)指的是通過(guò)以下幾種方式進(jìn)行的靜態(tài)調(diào)用:self::,parent::,static:: 以及 forward_static_call()??捎?get_called_class() 函數(shù)來(lái)得到被調(diào)用的方法所在的類名,static:: 則指出了其范圍。
該功能從語(yǔ)言內(nèi)部角度考慮被命名為"后期靜態(tài)綁定"。"后期綁定"的意思是說(shuō),static:: 不再被解析為定義當(dāng)前方法所在的類,而是在實(shí)際運(yùn)行時(shí)計(jì)算的。也可以稱之為"靜態(tài)綁定",因?yàn)樗梢杂糜冢ǖ幌抻冢╈o態(tài)方法的調(diào)用。
self:: 的限制
使用 self:: 或者 __CLASS__ 對(duì)當(dāng)前類的靜態(tài)引用,取決于定義當(dāng)前方法所在的類:
Example #1 self:: 用法
<?php class A { public static function who() { echo __CLASS__; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); ?>
以上例程會(huì)輸出:
A
后期靜態(tài)綁定的用法 后期靜態(tài)綁定本想通過(guò)引入一個(gè)新的關(guān)鍵字表示運(yùn)行時(shí)最初調(diào)用的類來(lái)繞過(guò)限制。簡(jiǎn)單地說(shuō),這個(gè)關(guān)鍵字能夠讓你在上述例子中調(diào)用 test() 時(shí)引用的類是 B 而不是 A。最終決定不引入新的關(guān)鍵字,而是使用已經(jīng)預(yù)留的 static 關(guān)鍵字。
Example #2 static:: 簡(jiǎn)單用法
<?php class A { public static function who() { echo __CLASS__; } public static function test() { static::who(); // 后期靜態(tài)綁定從這里開(kāi)始 } } class B extends A { public static function who() { echo __CLASS__; } } B::test(); ?>
以上例程會(huì)輸出:
B
Note: 在非靜態(tài)環(huán)境下,所調(diào)用的類即為該對(duì)象實(shí)例所屬的類。由于 $this-> 會(huì)在同一作用范圍內(nèi)嘗試調(diào)用私有方法,而 static:: 則可能給出不同結(jié)果。另一個(gè)區(qū)別是 static:: 只能用于靜態(tài)屬性。
Example #3 非靜態(tài)環(huán)境下使用 static::
<?php class A { private function foo() { echo "success!\n"; } public function test() { $this->foo(); static::foo(); } } class B extends A { /* foo() will be copied to B, hence its scope will still be A and * the call be successful */ } class C extends A { private function foo() { /* original method is replaced; the scope of the new one is C */ } } $b = new B(); $b->test(); $c = new C(); $c->test(); //fails ?>
以上例程會(huì)輸出:
success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Note: 后期靜態(tài)綁定的解析會(huì)一直到取得一個(gè)完全解析了的靜態(tài)調(diào)用為止。另一方面,如果靜態(tài)調(diào)用使用 parent:: 或者 self:: 將轉(zhuǎn)發(fā)調(diào)用信息。
Example #4 轉(zhuǎn)發(fā)和非轉(zhuǎn)發(fā)調(diào)用
<?php class A { public static function foo() { static::who(); } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { A::foo(); parent::foo(); self::foo(); } public static function who() { echo __CLASS__."\n"; } } class C extends B { public static function who() { echo __CLASS__."\n"; } } C::test(); ?>
以上例程會(huì)輸出:
A
C
C
下面示例分析了基于PHP后期靜態(tài)綁定功能解決在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。
先看如下代碼:
class Person { public static function status() { self::getStatus(); } protected static function getStatus() { echo "Person is alive"; } } class Deceased extends Person { protected static function getStatus() { echo "Person is deceased"; } } Deceased::status(); //Person is alive
很明顯,結(jié)果不是我們預(yù)期的,這是因?yàn)閟elf::取決于定義時(shí)所在的類,而不是運(yùn)行中的類。為了解決這個(gè)問(wèn)題,你可能會(huì)在繼承類中重寫(xiě)status()方法,更好的解決方案是PHP 5.3后添加了后期靜態(tài)綁定的功能。
代碼如下:
class Person { public static function status() { static::getStatus(); } protected static function getStatus() { echo "Person is alive"; } } class Deceased extends Person { protected static function getStatus() { echo "Person is deceased"; } } Deceased::status(); //Person is deceased
可見(jiàn),static::不在指向當(dāng)前所在的類,實(shí)際上,它是在運(yùn)行中計(jì)算的,強(qiáng)制獲取最終類的所有屬性。
因此,建議,以后不要再使用self::,使用static::
補(bǔ)充:
網(wǎng)友帖1
php的后期靜態(tài)綁定,怎么解釋?下面的這幅圖輸出是A,C,C
由圖的繼承關(guān)系可知:C徹底包含了B和A。
在看答案結(jié)果以前,他細(xì)觀察發(fā)現(xiàn),三個(gè)類里都有同一個(gè)名稱who()方法。
系統(tǒng)會(huì)用最后一個(gè)優(yōu)先級(jí)最高,進(jìn)一步的說(shuō),你幾乎沒(méi)法通過(guò)C去調(diào)用A、B內(nèi)的who(),只能重改方法,比如添加個(gè)getBWho(){echo B::who();}
然后通過(guò)C::getBWho();來(lái)調(diào)用B內(nèi)的who();
下面來(lái)看運(yùn)行結(jié)果:
test只在B中出現(xiàn),所以結(jié)果必然是test()中運(yùn)行的三個(gè)結(jié)果:
第一個(gè):靜態(tài)直接指名到姓的調(diào)用A內(nèi)靜態(tài)函數(shù),這沒(méi)有懸念,必然是A
第二個(gè):parent::是調(diào)用上一級(jí)的父類,在此題中為A,A中又直接調(diào)用static:who();上面說(shuō)過(guò)了,這個(gè)who()優(yōu)先級(jí)最高的在C里面,無(wú)論在你ABC中哪里調(diào)用,只要是static::who()必然是最后定義的那個(gè),覆蓋效應(yīng),如果想調(diào)用A里的必需指明A::who()或是通過(guò)去除static從作用域限制來(lái)實(shí)現(xiàn)。所以這個(gè)who()就是C中定義的who
第三個(gè):self::who與第二個(gè)類似的問(wèn)題,看樣該走B的,注意覆蓋效應(yīng),要想調(diào)用B內(nèi)的who必須得B::who(),因?yàn)楦呒?jí)的C已經(jīng)重寫(xiě)了這個(gè)方法,如果C中沒(méi)有who,肯定就是B,依次類推。所以必然還是調(diào)用C中的who;
所以答案為:ACC
代碼如下:
<?php class A { public static function foo() { static::who(); } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { A::foo(); parent::foo(); self::foo(); } public static function who() { echo __CLASS__."\n"; } } class C extends B { //public static function who() { // echo __CLASS__."\n"; //} } C::test(); ?>
輸出為:A B B
網(wǎng)友帖2
(還是針對(duì)上面圖中的代碼)
手冊(cè)不是說(shuō)得很清楚么
”后期綁定“的意思是說(shuō),static::不再被解析為定義當(dāng)前方法所在的類,而是在實(shí)際運(yùn)行時(shí)計(jì)算的。也可以稱之為”靜態(tài)綁定“,因?yàn)樗梢杂糜冢ǖ幌抻冢╈o態(tài)方法的調(diào)用。
#1說(shuō)的有個(gè)小問(wèn)題
【self::foo(); // 這個(gè)self實(shí)際上是C類。明白嗎? C::test() C繼承了B的test()方法】
不準(zhǔn)確,self還是B類,但是本身沒(méi)有覆寫(xiě)foo方法,所以就調(diào)用父類A的foo方法。
如果self實(shí)際是C類,那你試下self::foo();改成self::who();,應(yīng)當(dāng)打印C,但是打印B,這也正是self和static的區(qū)別。
<?php class A { public static function foo() { static::who(); } public static function who() { echo __CLASS__."\n"; } } class B extends A { public static function test() { A::foo(); parent::foo(); self::who(); } public static function who() { echo __CLASS__."\n"; } } class C extends B { public static function who() { echo __CLASS__."\n"; } } C::test(); ?>
輸出為:A C B
網(wǎng)友帖3
A::foo(); //A指代A類,訪問(wèn)A類的foo方法和who方法 parent::foo();//調(diào)用B類的父類——A的foo方法,并告訴foo方法最原始的調(diào)用者是C self::foo(); //self指代定義該方法的類,即B,但是B沒(méi)有定義foo方法,它將原始的調(diào)用者C向上傳遞, // 訪問(wèn)父類的foo方法,最后訪問(wèn)c的who方法;
所以這就回答了樓上的疑問(wèn):若是把self::foo(); 改成self::who(),因?yàn)閟elf指代B,而B(niǎo)有who方法,所以結(jié)果是變成了B
靜態(tài)調(diào)用使用 parent:: 或者 self:: 將轉(zhuǎn)發(fā)原始調(diào)用信息。
更多關(guān)于PHP相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門(mén)教程》、《PHP基本語(yǔ)法入門(mén)教程》、《PHP運(yùn)算與運(yùn)算符用法總結(jié)》、《PHP網(wǎng)絡(luò)編程技巧總結(jié)》、《PHP數(shù)組(Array)操作技巧大全》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門(mén)教程》及《php常見(jiàn)數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家PHP程序設(shè)計(jì)有所幫助。
相關(guān)文章
PHP內(nèi)置的Math函數(shù)效率測(cè)試
這篇文章主要介紹了PHP內(nèi)置的Math函數(shù)效率測(cè)試,以實(shí)例形式測(cè)試了相關(guān)的PHP內(nèi)置數(shù)學(xué)運(yùn)算函數(shù)的執(zhí)行時(shí)間,分析其運(yùn)行效率,需要的朋友可以參考下2014-12-12thinkphp中連接oracle時(shí)封裝方法無(wú)法用的解決辦法
本篇文章是對(duì)thinkphp中連接oracle時(shí)封裝方法無(wú)法用的解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06PHP fopen()和 file_get_contents()應(yīng)用與差異介紹
這篇文章主要介紹了PHP fopen()和 file_get_contents()應(yīng)用與差異,需要的朋友可以參考下2014-03-03簡(jiǎn)單談?wù)刾hp中的unicode和utf8編碼
本文給大家深入討論了unicode和utf8這兩種編碼的關(guān)系,理解好了會(huì)發(fā)現(xiàn)網(wǎng)上一些舊的東西,是嚴(yán)重多余兼過(guò)期的,因?yàn)閺膗tf-8流行開(kāi)始到現(xiàn)在,早已經(jīng)由原來(lái)六字節(jié)可變編碼到實(shí)際完全居于unicode(UCS-2)的穩(wěn)定階段。2015-06-06php file_get_contents取文件中數(shù)組元素的方法
下面小編就為大家?guī)?lái)一篇php file_get_contents取文件中數(shù)組元素的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04PHP5.3與5.5廢棄與過(guò)期函數(shù)整理匯總
這篇文章主要介紹了PHP5.3與5.5廢棄與過(guò)期函數(shù),需要的朋友可以參考下2014-07-07