自 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
*/