php self this static,PHP 中 self、static、$this 的区别和后期静态绑定详解
本篇文章給大家分享的內容是關于PHP 中 self、static、$this 的區別和后期靜態綁定詳解,有著一定的參考價值,有需要的朋友可以參考一下
self、static 和 $this 的區別
為了更好地理解 self、static 和 $this 的區別,先來看一個示例。<?phpclass A { protected $name = 'A'; static $alias = 'a'; const HASH = 'md5'; public function dd() { echo $this->name; echo '--'; echo static::$alias; echo '--'; // 后期靜態綁定
echo static::HASH; echo '--'; // 后期靜態綁定
echo self::$alias; echo '--'; echo self::HASH; echo '--';
var_dump(new self); echo '--';
var_dump($this); echo '--';
var_dump(new static); echo '
'; // 后期靜態綁定
} public static function who() { echo __CLASS__; echo ' [ This is A ]'; echo '
';
} public static function test() { self::who();
} public static function test2() { static::who(); // 后期靜態綁定
} public static function getInstance() {
var_dump(new self); echo '--';
var_dump(new static); echo '
'; // 后期靜態綁定
}
}class B extends A { protected $name = 'B'; static $alias = 'b'; const HASH = 'sha1'; public static function who() { echo __CLASS__; echo ' [ This is B ]'; echo '
';
}
}class C extends B { public static function who() { echo __CLASS__; echo ' [ This is C]'; echo '
';
}
}
(new A)->dd(); // A--a--md5--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#2 (1) { ["name":protected]=> string(1) "A" }(new B)->dd(); // B--b--sha1--a--md5--object(A)#2 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" } --object(B)#2 (1) { ["name":protected]=> string(1) "B" }A::who(); // A [ This is A ]B::who(); // B [ This is B ]A::test(); // A [ This is A ]B::test(); // A [ This is A ]A::test2(); // A [ This is A ]B::test2(); // B [ This is B ]C::test2(); // C [ This is C]A::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(A)#1 (1) { ["name":protected]=> string(1) "A" }B::getInstance(); // object(A)#1 (1) { ["name":protected]=> string(1) "A" } --object(B)#1 (1) { ["name":protected]=> string(1) "B" }
總結說明:self 和 __CLASS__,都是對當前類的靜態引用,取決于定義當前方法所在的類。也就是說,self 寫在哪個類里面, 它引用的就是誰。
$this 指向的是實際調用時的對象,也就是說,實際運行過程中,誰調用了類的屬性或方法,$this 指向的就是哪個對象。但 $this 不能訪問類的靜態屬性和常量,且 $this 不能存在于靜態方法中。
static 關鍵字除了可以聲明類的靜態成員(屬性和方法)外,還有一個非常重要的作用就是后期靜態綁定。
self 可以用于訪問類的靜態屬性、靜態方法和常量,但 self 指向的是當前定義所在的類,這是 self 的限制。
$this 指向的對象所屬的類和 static 指向的類相同。
static 可以用于靜態或非靜態方法中,也可以訪問類的靜態屬性、靜態方法、常量和非靜態方法,但不能訪問非靜態屬性。
靜態調用時,static 指向的是實際調用時的類;非靜態調用時,static 指向的是實際調用時的對象所屬的類。
后期靜態綁定
后期靜態綁定(也叫延遲靜態綁定),可用于在繼承范圍內引用靜態調用的類,也就是代碼運行時最初調用的類。
后期靜態綁定本想通過引入一個新的關鍵字來表示,但最終還是沿用了 static 關鍵字。
工作原理
確切地說,static 后期靜態綁定的工作原理是存儲了上一個非轉發調用(non-forwarding call)的類名。
當進行靜態方法調用時,該類名(static指向的類名)為明確指定的那個(通常是 :: 運算符的左側部分),即實際調用時的類。
如上述示例中的:A::test2(); B::test2();
static 和 self 的區別:self 可以用于訪問類的靜態屬性、靜態方法和常量,但 self 指向的是當前定義所在的類,這是 self 的限制。
static 也可以用于訪問類的靜態屬性、靜態方法和常量,static 指向的是實際調用時的類。
當進行非靜態方法調用時,該類名(static指向的類名)為該對象所屬的類,即實際調用時的對象所屬的類。
如上述示例中的:(new A)->dd();
(new B)->dd();
static 和 $this 有點類似,但又有區別:$this 指向的對象所屬的類和 static 指向的類相同。
$this 不能用于靜態方法中,也不能訪問類的靜態屬性和常量。
$this 指向的是實際調用的對象。
static 可以用于靜態或非靜態方法中,也可以訪問類的靜態屬性、靜態方法、常量和非靜態方法,但不能訪問非靜態屬性。
static 指向的是實際調用時的對象所屬的類。
轉發調用(forwarding call)
所謂的轉發調用(forwarding call)指的是通過以下幾種方式進行的靜態調用:self::,parent::,static:: 以及 forward_static_call() 。
可用 get_called_class() 函數來獲取被調用的方法所在的類名。
以下四種形式的調用,都是轉發調用:self::
parent::
static::
forward_static_call()
除此之外的調用,就是非轉發調用。
非轉發調用(non-forwarding call)
后期靜態綁定的工作原理是存儲了上一個非轉發調用(non-forwarding call)的類名。
通過具體的類名或具體的對象進行的調用都是非轉發調用。
比如:A::test2();
B::test2();
(new A)->dd();
(new B)->dd();
注意事項
非靜態環境下的私有方法的查找順序
在非靜態環境下,在類的非靜態方法中,使用 $this 和 static 調用類的私有方法時,執行方式有所不同。$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 '
';
} public function test () { $this -> foo (); static:: foo (); echo '
';
}
}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'
關于后期靜態綁定的解析
后期靜態綁定的解析會一直到取得一個完全解析了的靜態調用為止。如果靜態調用使用了 parent:: 或者 self:: 等轉發調用的形式,將會轉發調用信息。<?phpclass 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 '
';
} 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
static 后期靜態綁定的工作原理是存儲了上一個非轉發調用(non-forwarding call)的類名。請記住這句話。
下面的例子是非轉發調用。A::foo(); // 輸出 AB::foo(); // 輸出 BC::foo(); // 輸出 C
后期靜態綁定 static ,是定義在了 foo() 方法中,哪個類通過非轉發調用的形式調用 foo() 方法, foo() 方法中的 static 指向的就是哪個類。
但是,如果通過轉發調用的形式,調用 foo() 方法,如:parent :: foo ();self :: foo ();static::foo();forward_static_call(['A', 'foo']);
那么,就以轉發調用代碼所在的方法 test() 為準,哪個類通過非轉發調用的形式調用 test() 方法, foo() 方法中的 static 指向的就是哪個類。
假如調用 test() 方法時,也采用了轉發調用的形式,如:public static function test2() { self::test();
}
那么,就以 test2() 方法為準 ... 依次類推。
也就是說,在使用了后期靜態綁定的基類中,后期靜態綁定所在的方法如果被轉發調用,則 static 的指向,會一直向上追溯,直到遇到非轉發調用的形式。
相關推薦:
總結
以上是生活随笔為你收集整理的php self this static,PHP 中 self、static、$this 的区别和后期静态绑定详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php error docref,PHP
- 下一篇: PHP随机输出视频API源码,php 3