什麼叫後期靜態綁定呢?數組
首先,咱們經過一段代碼來引入後期靜態綁定這一律念:測試
class A { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { self::who(); } } class B extends A { public static function who() { echo __CLASS__, PHP_EOL; } } B::test(); // A
在這段代碼中,咱們使用了self關鍵字,當使用B類調用test()靜態方法時,self指向的是A類的who()方法,所以,輸出的是A。別激動,這是普通的靜態綁定。self關鍵字調用的內容取決於它定義時所在的類。也就是說無論怎麼繼承,用哪一個子類來調用test()方法,self關鍵字都會調用的是A類的who()方法。code
然後期靜態綁定呢?其實就有點像實例化的類對象,每一個實例化的對象,調用的都是自身,而不是父類的屬性方法。普通的靜態調用可不是這樣,可是現實中咱們又有這樣的需求,就像實例化對象的調用方式同樣來調用靜態屬性方法,這時,咱們就可使用static關鍵字來實現後期靜態綁定。對象
class C { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { static::who(); } } class D extends C { public static function who() { echo __CLASS__, PHP_EOL; } } D::test(); // D
當使用static關鍵字後,這裏D類調用的test()方法內部調用的who()就是D類本身了。繼承
官方文檔中的定義以下:文檔
當進行靜態方法調用時,該類名即爲明確指定的那個(一般在 :: 運算符左側部分);當進行非靜態方法調用時,即爲該對象所屬的類。get
該功能從語言內部角度考慮被命名爲「後期靜態綁定」。「後期綁定」的意思是說,static:: 再也不被解析爲定義當前方法所在的類,而是在實際運行時計算的。也能夠稱之爲「靜態綁定」,由於它能夠用於(但不限於)靜態方法的調用。io
除了self和static關鍵字外,咱們還有一個parent關鍵字,這個關鍵字的意義就很明顯了,調用父類的靜態內容。咱們同時用三個關鍵字一塊兒來進行測試:function
class E { public static function who() { echo __CLASS__, PHP_EOL; } public static function test() { self::who(); static::who(); } } class F extends E { public static function who() { echo __CLASS__, PHP_EOL; } } class G extends F { public static function who() { parent::who(); echo __CLASS__, PHP_EOL; } } G::test(); // E // F // G
最後,咱們再來看兩個PHP的方法,一個是get_called_class()方法,用來獲取當前調用的是哪一個類。在靜態方法中能夠根據調用方式判斷當前類是哪一個類來進行其餘的業務邏輯操做。另外一個是forward_static_call()方法,用於靜態方法的調用。class
class H { public static function who() { echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL; } public static function test() { echo get_called_class(), PHP_EOL; forward_static_call('who', 'a', 'b'); // xxx:a,b forward_static_call(['I', 'who'], 'c', 'd'); // I:c,d forward_static_call_array(['H', 'who'], ['e', 'f']); // H:e,f } } class I extends H { public static function who() { echo __CLASS__ . ':' . join(',', func_get_args()), PHP_EOL; } } function who() { echo 'xxx:' . join(',', func_get_args()), PHP_EOL; } H::test(); // H // xxx:a,b // I:c,d // H:e,f I::test(); // I // xxx:a,b // I:c,d // H:e,f
注意,若是forward_static_call()不指定類名的話,將調用全局的方法。forward_static_call_array()則是將參數使用數組進行傳遞。