這篇文章給大家分享的內容是關於PHP 中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 '<br>'; // 后期静态绑定 } public static function who() { echo __CLASS__; echo ' [ This is A ]'; echo '<br>'; } 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 '<br>'; // 后期静态绑定 } }class B extends A { protected $name = 'B'; static $alias = 'b'; const HASH = 'sha1'; public static function who() { echo __CLASS__; echo ' [ This is B ]'; echo '<br>'; } }class C extends B { public static function who() { echo __CLASS__; echo ' [ This is C]'; echo '<br>'; } } (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)指的是透過以下幾種方式進行的靜態呼叫:self::,parent::, static:: 以及forward_static_call() 。
可用 get_called_class() 函數來取得被呼叫的方法所在的類別名稱。
以下四個形式的調用,都是轉發調用:
self::
parent::
static::
forward_static_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 '<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'
后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。如果静态调用使用了 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 '<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
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、static、$this 的差異與後期靜態綁定詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!