PHP的後期靜態繫結
阿新 • • 發佈:2018-11-30
參考:https://blog.csdn.net/lamp_yang_3533/article/details/79912453
1.定義
後期靜態繫結(也叫延遲靜態繫結),可用於在繼承範圍內引用靜態呼叫的類
2.工作原理
static 後期靜態繫結的工作原理是儲存了上一個非轉發呼叫(non-forwarding call)的類名。
- 當進行靜態方法呼叫時,該類名(static指向的類名)為明確指定的那個(通常是 :: 運算子的左側部分),即實際呼叫時的類。
- 當進行非靜態方法呼叫時,即為該物件所屬的類。
- "後期繫結"的意思是說,static:: 不再被解析為定義當前方法所在的類,而是在實際執行時計算的。
3.轉發呼叫
所謂的轉發呼叫(forwarding call)指的是通過以下幾種方式進行的靜態呼叫:self::,parent::,static:: 以及 forward_static_call() 。 可用 get_called_class() 函式被呼叫的方法所在的類名。
4.非轉發呼叫
通過具體的類名或具體的物件進行的呼叫都是非轉發呼叫,即非上面四種方式的呼叫都是非轉發呼叫。
5.非靜態環境下$this和static呼叫的區別
①$this 會優先尋找所在定義範圍(父類)中的私有方法,如果存在就呼叫。 ②static 是先到它指向的類(子類)中尋找私有方法,如果找到了就會報錯,因為私有方法只能在它所定義的類內部呼叫;如果沒找到,再去所在定義範圍(父類)中尋找該私有方法,如果存在就呼叫。
<?php class A { private function foo () { var_dump($this); echo '--'; var_dump(new static); echo '--'; echo __CLASS__; echo '--'; echo get_called_class(); echo非靜態環境下$this和static呼叫區別'<br>'; } public function test () { $this -> foo (); static:: foo (); echo '<br>'; } } class B extends A { } class C extends A { private function foo () { echo 'this is C'; } } (new B())->test(); (new C())->test(); ?> //輸出結果 object(B)#1 (0) { } --object(B)#2 (0) { } --A--B object(B)#1 (0) { } --object(B)#2 (0) { } --A--B object(C)#1 (0) { } --object(C)#2 (0) { } --A--C Fatal error: Uncaught Error: Call to private method C::foo() from context 'A' in /usercode/file.php:14 Stack trace: #0 /usercode/file.php(28): A->test() #1 {main} thrown in /usercode/file.php on line 14
6.後期靜態繫結解析
後期靜態繫結的解析會一直到取得一個完全解析了的靜態呼叫為止。如果靜態呼叫使用了 parent:: 或者 self:: 等轉發呼叫的形式,將會轉發呼叫資訊。
<?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 (); static::foo(); forward_static_call(['A', 'foo']); echo '<br>'; } public static function who () { echo __CLASS__ . "\n" ; } } class C extends B { public static function who () { echo __CLASS__ . "\n" ; } public static function test2() { self::test(); } } class D extends C { public static function who () { echo __CLASS__ . "\n" ; } } B::foo(); B::test(); C::foo(); C::test(); D::foo(); D::test2(); ?> //輸出結果 B A B B B B C A C C C C D A D D D D後期靜態繫結