php5 3後靜態繫結用法詳解

2022-10-06 08:48:08 字數 4182 閱讀 7943

手冊原文:

自 php 5.3.0 起,php 增加了乙個叫做後期靜態繫結的功能,用於在繼承範圍內引用靜態呼叫的類。

準確說,後期靜態繫結工作原理是儲存了在上乙個"非**呼叫"(non-forwarding call)的類名。當進行靜態方法呼叫時,該類名即為明確指定的那個(通常在 :: 運算子左側部分);當進行非靜態方法呼叫時,即為該物件所屬的類。所謂的"**呼叫"(forwarding call)指的是通過以下幾種方式進行的靜態呼叫:self::,parent::,static:: 以及 forward_static_call()。可用 get_called_class() 函式來得到被呼叫的方法所在的類名,static:: 則指出了其範圍。

該功能從語言內部角度考慮被命名為"後期靜態繫結"。"後期繫結"的意思是說,static:: 不再被解析為定義當前方法所在的類,而是在實際執行時計算的。也可以稱之為"靜態繫結",因為它可以用於(但不限於)靜態方法的呼叫。

self:: 的限制

使用 self:: 或者 __class__ 對當前類的靜態引用,取決於定義當前方法所在的類:

example #1 self:: 用法

<?php class a

public static function test()

}class b extends a

}b::test();

?>

以上例程會輸出:

a後期靜態繫結的用法 後期靜態繫結本想通過引入乙個新的關鍵字表示執行時最初呼叫的類來繞過限制。簡單地說,這個關鍵字能夠讓你在上述例子中呼叫 test() 時引用的類是 b 而不是 a。最終決定不引入新的關鍵字,而是使用已經預留的 static 關鍵字。

example #2 static:: 簡單用法

<?php class a

public static function test()

}class b extends a

}b::test();

?>

以上例程會輸出:

bnote: 在非靜態環境下,所呼叫的類即為該物件例項所屬的類。由於 $this-> 會在同一作用範圍內嘗試呼叫私有方法,而 static:: 則可能給出不同結果。另乙個區別是 static:: 只能用於靜態屬性。

example #3 非www.cppcns.com靜態環境下使用 static::

<?php class a

public function test()

}class b extends a

class c extends a

}$b = new b();

$b->test();

$c = new c();

$c->test(); //fails

?>

以上例程會輸出:

success!

success!

success!

fatal error: call to private method c::foo() from context 'a' in /tmp/test.php on line 9

note: 後期靜態繫結的解析會一直到取得乙個完全解析了的靜態呼叫為止。另一方面,如果靜態呼叫使用 parent:: 或者 self:: 將**呼叫資訊。

example #4 **和非**呼叫

<?php class a

public static function who()

}class b extends a

public static function who()

}class c extends b

}c::test();

?>

以上例程會輸出:ac

c下面示例分析了基於php後期靜態繫結功能解決在繼承範圍內引用靜態呼叫的類。

先看如下**:

class person

protected static function getstatus()

}class deceased extends person

}deceased::status(); //person is alive

很明顯,結果不是我們預期的,這是因為self::取決於定義時所在的類,而不是執行中的類。為了解決這個問題,你可能會在繼承類中重寫status()方法,更好的解決方案是php 5.3後新增了後期靜態繫結的功能。

**如下:

class person

protected static function getstatus()

}class deceased extends person

}deceased::status(); //person is deceased

可見,static::不在指向當前所在的類,實際上,它是在執行中計算的,強制獲取最終類的所有屬性。

因此,建議,以後不要再使用self::,使用static::

補充:網友帖1

php的後期靜態繫結,怎麼解釋?下面的這幅圖輸出是a,c,c

由圖的繼承關係可知:c徹底包含了b和a。

在看答案結果以前,他細觀察發現,三個類裡都有同乙個名稱who()方法。

系統會用最後乙個優先順序最高,進一步的說,你幾乎沒法通過c去呼叫a、b內的who(),只能重改方法,比如新增個getbwho()

然後通過c::getbwho();來呼叫b內的who();

下面來看執行結果:

test只在b**現,所以結果必然是test()中執行的三個結果:

第乙個:靜態直接指名到姓的呼叫a內靜態函式,這沒有懸念,必然是a

第二個:parent::是呼叫上一級的父類,在此題中為a,a中又直接呼叫static:who();上面說過了,這個who()優先順序最高的在c裡面,無論在你abc中**呼叫,只要是static::who()必然是最後定義的那個,覆蓋效應,如果想呼叫a裡的必需指明a::who()或是通過去除static從作用域限制來實現。所以這個who()就是c中定義的who

第三個:self::who與第二個類似的問題,看樣該走b的,注意覆蓋效應,要想呼叫b內的who必須得b::who(),因為更高階的c已經重寫了這個方法,如果c中沒有who,肯定就是b,依次類推。所以必然還是呼叫c中的who;

所以答案為:acc

**如下:

<?php class a

public static function who()

}class b extends a

public static function who()

}class c extends b

}c::test();

?>

輸出為:a b b

網友帖2

(還是針對上面圖中的**)

手冊不是說得很清楚麼

」後期繫結「的意思是說,static::不再被解析為定義當前方法所在的類,而是在實際執行時計算的。也可以稱之為」靜態繫結「,因為它可以用於(但不限於)靜態方法的呼叫。

#1說的有個小問題

【self::foo(); // 這個self實際上是c類。明白嗎? c::test() c繼承了b的test()方法】

不準確,self還是b類,但是本身沒有覆寫foo方法,所以就呼叫父類a的foo方法。

如果self實際是c類,那你試下self::foo();改成self::who();,應當列印c,但是列印b,這也正是self和static的區別。

<?php class a

public static function who()

}class b extends a

public static function who()

}class c extends b

}c::test();

?>

輸出為:a c b

網友帖3

a::foo(); //a指代a類,訪問a類的foo方法和who方法

parent::foo();//呼叫b類的父類——a的foo方法,並告訴foo方法最原始的呼叫者是c程式設計客棧

self::foo(); //self指代定義該方法的類,即b,但是b沒有定義foo方法,它將原始的呼叫者c向上傳遞,

// 訪問父類的foo方法,最後訪問c的who方法;

所以這就回答了樓上的疑問:若是把self::foo(); 改成self::who(),因為self指代b,而b有who方法,所以結果是變成程式設計客棧了b

靜態呼叫使用 par程式設計客棧ent:: 或者 self:: 將**原始呼叫資訊。

php5 3新特性之延遲靜態繫結

基於php版本 5.3.5 php5.3 以後引入了延遲靜態繫結 static 關鍵字 類似於 self 關鍵字 但它指向的是被呼叫的類 document 而不是包含類 domainobject static 和 self 的區別 主要的作用就是,彌補了原先的不足,原先子類可以用parent找到父類...

php5 3 延遲靜態繫結 static關鍵字

1 傳統模式 這段 能很好工作,但大量的重複 很煩人,不想為每個domainobject子類都建立這段相同 吧?2 34abstract class domainobject 56 class user extends domainobject712 13public static function...

php 5 3中的類的別名的用法

在php 5.3中,要是想引入一些類的名字很長的話,書寫起來比較麻煩,這個時候 可以用php 5.3的類的別名的用法,舉例說明如下 class irrational long class name class alias irrational long class name shortalias s...