PHP面向?qū)ο?后期靜態(tài)綁定

自 PHP 5.3.0 起谚咬,PHP 增加了一個叫做后期靜態(tài)綁定的功能,用于在繼承范圍內(nèi)引用靜態(tài)調(diào)用的類。 

說明

準(zhǔn)確說,后期靜態(tài)綁定工作原理是存儲了在==上一個==“==非轉(zhuǎn)發(fā)調(diào)用==”(non-forwarding call)的類名嫉称。當(dāng)進(jìn)行靜態(tài)方法調(diào)用時,該類名即為明確指定的那個(通常在運算符 : : 左側(cè)部分)禾乘;當(dāng)進(jìn)行非靜態(tài)方法調(diào)用時澎埠,即為該對象所屬的類。

所謂的“轉(zhuǎn)發(fā)調(diào)用”(forwarding call)指的是通過以下幾種方式進(jìn)行的靜態(tài)調(diào)用:self::始藕,parent::蒲稳,static:: 以及 forward_static_call()∥榕桑可用 get_called_class() 函數(shù)來得到被調(diào)用的方法所在的類名江耀,static:: 則指出了其范圍。即在進(jìn)行靜態(tài)調(diào)用時未指名類名的調(diào)用屬于轉(zhuǎn)發(fā)調(diào)用诉植。

非轉(zhuǎn)發(fā)調(diào)用: 轉(zhuǎn)發(fā)調(diào)用其實就是明確指定類名的靜態(tài)調(diào)用(foo::bar())和非靜態(tài)調(diào)用($foo->bar())祥国。即明確地指定類名的靜態(tài)調(diào)用和非靜態(tài)調(diào)用

該功能從語言內(nèi)部角度考慮被命名為“后期靜態(tài)綁定”×狼唬“后期綁定”的意思是說舌稀,static:: 不再被解析為定義當(dāng)前方法所在的類,而是在實際運行時計算的灼擂。也可以稱之為“靜態(tài)綁定”壁查,因為它可以用于(但不限于)靜態(tài)方法的調(diào)用。

1.self::限制 (靜態(tài)方法調(diào)用)

使用 self:: 或者 __CLASS__ 對當(dāng)前類的靜態(tài)引用剔应,取決于定義當(dāng)前方法所在的類:
<?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();  
?>   
//解釋:定義當(dāng)前test方法的類為A睡腿,所以self代表類A。
//輸出結(jié)果為:A
<?php  
class A {  
    public static function who() {  
        echo __CLASS__;  
    }  
    
    public static function test() {  
        static::who(); // 后期靜態(tài)綁定從這里開始  
    }  
}  
  
class B extends A {  
    public static function who() {  
        echo __CLASS__;  
    }  
}  
  
B::test();  

/*
解釋:static::不再被解析為定義當(dāng)前方法所在的類峻贮,而是在實際運行時計算的席怪。
 
B::test(); 這是一個非轉(zhuǎn)發(fā)的靜態(tài)調(diào)用(因為::前面有類名B),進(jìn)入test()方法纤控,static::who() 這個是一個轉(zhuǎn)發(fā)性的靜態(tài)調(diào)用挂捻,按照后期靜態(tài)綁定可以得到,他的上一個非轉(zhuǎn)發(fā)靜態(tài)類名是B嚼黔。因此static::who()可以理解成執(zhí)行的是B::foo(),輸出的結(jié)果是B

//輸出結(jié)果為:B

*/

2.非靜態(tài)環(huán)境下使用 static:: (非靜態(tài)方法調(diào)用)

在非靜態(tài)環(huán)境下细层,所調(diào)用的類即為該對象實例所屬的類。由于 $this-> 會在==同一作用范圍內(nèi)==嘗試調(diào)用私有方法唬涧,而static:: 則可能給出不同結(jié)果疫赎。另一個區(qū)別是static:: 只能用于靜態(tài)屬性。

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();  


/*解釋:類C中沒有test()方法碎节,所以類C的實例調(diào)用父類A中的test方法捧搞,此時處于父類A的作用于域中,無法調(diào)用C::foo()這私有方法,所以在使用static::foo()時會報錯Fatal error: Call to private method C::foo() from context 'A' ,但$this會嘗試調(diào)用同一作用域中的私有方法胎撇,即無法調(diào)用當(dāng)前對象c的方法介粘,就調(diào)用它父類的。
輸出結(jié)果為:

success! success! success! 



( ! ) Fatal error: Call to private method C::foo() from context 'A' 

*/
get_called_class

get_called_class — 后期靜態(tài)綁定("Late Static Binding")類的名稱

get_called_class();獲取靜態(tài)方法調(diào)用的類名晚树。

class A {
    private function foo() {
        echo  get_called_class() . '<br>';
    }
    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();
$b = new C();
$b->test();

//輸出結(jié)果: B B C 

3.轉(zhuǎn)發(fā)調(diào)用信息

后期靜態(tài)綁定的解析會一直到取得一個完全解析了的靜態(tài)調(diào)用為止姻采。另一方面,如果靜態(tài)調(diào)用使用 parent:: 或者self:: 將轉(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();  

/*   
解釋:
所謂的"轉(zhuǎn)發(fā)調(diào)用"(forwarding call)指的是通過以下幾種方式進(jìn)行的靜態(tài)調(diào)用:self::慨亲,parent::,static:: 以及forward_static_call()宝鼓⌒炭茫可用get_called_class() 函數(shù)來得到被調(diào)用的方法所在的類名,static:: 則指出了其范圍愚铡。 

A::foo() 靜態(tài)直接指名到姓的調(diào)用A內(nèi)靜態(tài)函數(shù)蛉签,輸出A

 parent::foo()是調(diào)用上一級的父類中的方法 ,此處為A,self::調(diào)用自身(類B)的foo()方法沥寥,類B中沒有foo()方法碍舍,則調(diào)用類A中的foo()方法。

A,B,C三個類里都有同一個名稱who()方法邑雅,根據(jù)覆蓋效應(yīng)乒验。系統(tǒng)會用優(yōu)先級最高的,即C中的蒂阱。輸出:C C
*/
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市狂塘,隨后出現(xiàn)的幾起案子录煤,更是在濱河造成了極大的恐慌,老刑警劉巖荞胡,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妈踊,死亡現(xiàn)場離奇詭異,居然都是意外死亡泪漂,警方通過查閱死者的電腦和手機廊营,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來萝勤,“玉大人露筒,你說我怎么就攤上這事〉凶浚” “怎么了慎式?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我瘪吏,道長癣防,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任掌眠,我火速辦了婚禮蕾盯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓝丙。我一直安慰自己级遭,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布迅腔。 她就那樣靜靜地躺著装畅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沧烈。 梳的紋絲不亂的頭發(fā)上掠兄,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音锌雀,去河邊找鬼蚂夕。 笑死,一個胖子當(dāng)著我的面吹牛腋逆,可吹牛的內(nèi)容都是我干的婿牍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼惩歉,長吁一口氣:“原來是場噩夢啊……” “哼等脂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撑蚌,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤上遥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后争涌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粉楚,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年亮垫,在試婚紗的時候發(fā)現(xiàn)自己被綠了模软。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡饮潦,死狀恐怖燃异,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情继蜡,我是刑警寧澤特铝,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布暑中,位于F島的核電站,受9級特大地震影響鲫剿,放射性物質(zhì)發(fā)生泄漏鳄逾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一灵莲、第九天 我趴在偏房一處隱蔽的房頂上張望雕凹。 院中可真熱鬧,春花似錦政冻、人聲如沸枚抵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汽摹。三九已至,卻和暖如春苦锨,著一層夾襖步出監(jiān)牢的瞬間逼泣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工舟舒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拉庶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓秃励,卻偏偏與公主長得像氏仗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子夺鲜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理皆尔,服務(wù)發(fā)現(xiàn),斷路器币励,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,101評論 1 32
  • 09120肖遜 今天要分享的是Dorothy Kunhardt《Pat the Bunny》床佳,這是本是非常適合低幼...
    遜仔閱讀 364評論 0 1
  • 你眼睛眨了一下 時間就開花 隔壁家的小胖貓 趴在窗臺上望你 你沖她笑一笑 天色都變好 四月的清晨 微風(fēng)比往日蕩漾 ...
    顏延閱讀 145評論 1 2
  • 似乎每一次的離開都是不想面對曾經(jīng)的過往,每一次新的開始都不參雜任何舊的人物杆麸「榻火車伊駛,窗外的景物漸行漸遠(yuǎn)昔头,過去十九...
    南渡北飛閱讀 188評論 1 1