PHP常見概念混淆(七)之self、static、parent的區別
阿新 • • 發佈:2018-08-07
sta parent tst 執行 pub call 例子 turn function
前言
首先,這個 static
符號跟 static(靜態)關鍵字
不是一個東西。這三個符號在PHP對象中共有兩種用法:
- 在類內部,可以使用
new self
、new static
、new parent
創建新對象 - 可以使用
self::
、static::
、parent::
調用靜態變量和方法。
創建新對象
<?php class test{ public static function test_self(){ return new self(); } public static function test_static(){ return new static(); } public static function test_parent(){ return new parent(); } } class test2 extends test{ public static function test_parent(){ return new parent(); } } class test3 extends test2{ } echo get_class(test::test_self()); //test echo get_class(test::test_static()); //test echo get_class(test2::test_self()); //test echo get_class(test2::test_static()); //test2 echo get_class(test2::test_parent()); //test echo get_class(test3::test_self()); //test echo get_class(test3::test_static()); //test3 echo get_class(test3::test_parent()); //test
由以上這個例子可以得出:
new self
創建的對象是定義new self
的類創建的對象new static
創建的對象是執行new static
的類創建的對象new parent
創建的對象是定義new parent
的父類創建的對象(PHP5.3引進)
調用靜態變量
概念
- 轉發調用(forwarding call):所謂的"轉發調用"指的是通過以下幾種方式進行的靜態調用:
self::
,parent::
,static::
以及forward_static_call()
.即在進行靜態調用時未指名類名的調用屬於轉發調用。 - 非轉發調度(non-forwarding call):非轉發調用其實就是明確指定類名的靜態調用(foo::bar())和非靜態調用($foo->bar())。即明確地指定類名的靜態調用和非靜態調用。
- 後期靜態綁定(Late Static Bindings ):"後期靜態綁定"的意思是說,static:: 不再被解析為定義當前方法所在的類,而是在實際運行時計算的。
不存在繼承的時候
self和static無區別。
- 在靜態函數中,self和static可以調用靜態屬性和靜態方法(沒有實例化類,因此不能呼叫非靜態的屬性和方法)。
在非靜態函數中, self和static可以調用非靜態屬性和非靜態方法。
<?php class Demo{ public static $static; public $Nostatic; public function __construct(){ self::$static = "static"; $this->Nostatic = "Nostatic"; } public static function get(){ return __CLASS__; } public function show(){ return "this is function show with ".$this->Nostatic; } public function test(){ echo Demo::$static."\n"; //使用類型調用靜態屬性 static echo Demo::get()."\n"; //使用類名調用非靜態方法 Demo echo Demo::show()."\n"; //使用類名調用靜態方法 this is function show with Nostatic echo self::$static."\n"; //self調用靜態屬性 static echo self::get()."\n"; //self調用非靜態方法 Demo echo self::show()."\n"; //self調用靜態方法 this is function show with Nostatic echo static::$static."\n";//static調用靜態屬性 static echo static::get()."\n";//static調用非靜態方法 Demo echo static::show()."\n"; //static調用靜態方法 this is function show with Nostatic } } $obj = new Demo(); $obj->test();
存在繼承關系的時候
- self調用的方法和屬性始終表示當前類的方法和屬性
- static調用的方法和屬性為當前執行的類的方法和屬性
parent調用的方法和屬性為父類的方法和屬性
<?php class A{ static $test = "AAA"; static function getClassName(){ return "A"; } function getClassName2(){ return "AA"; } static function testSelf(){ echo self::getClassName(); echo "\n"; echo self::getClassName2(); echo "\n"; echo self::$test; } static function testStatic(){ echo static::getClassName(); echo "\n"; echo static::getClassName2(); echo "\n"; echo static::$test; } } class B extends A{ static $test = "BBB"; static function getClassName(){ return "B"; } function getClassName2(){ return "BB"; } static function testParent(){ echo parent::getClassName(); echo "\n"; echo parent::getClassName2(); echo "\n"; echo parent::$test; } } class C extends B{ static $test = "CCC"; static function getClassName(){ return "C"; } function getClassName2(){ return "CC"; } static function testParent(){ echo parent::getClassName(); echo "\n"; echo parent::getClassName2(); echo "\n"; echo parent::$test; } } B::testSelf(); // A AA AAA echo "\n"; B::testStatic();// B BB BBB echo "\n"; B::testParent();// A AA AAA echo "\n"; C::testSelf(); // A AA AAA echo "\n"; C::testStatic(); // C CC CCC echo "\n"; C::testParent(); // B BB BBB
解析一下手冊裏的例子
<?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();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
最後輸出為 A C C
單獨拿出進行分析
public static function test() {
A::foo();
parent::foo();
self::foo();
}
A::foo()
:非轉發請求,直接調用A的foo()
方法,在任何地方調用結果都是一樣的parent::foo()
:在B類中寫著,調用B的父類A的方法foo()
(parent的用法);A類中的foo()
中執行static::who()
,尋找上一個非轉發請求的類名(在A類的foo()
方法中寫上get_called_class()
,可得為C,由此可知就是當前執行的類),所以調用C類的who()
方法(這一步就可以理解為後期靜態綁定,即為static的用法);C類中重寫了who()
方法,所以結果為C;如果去掉C類中的who()
方法,會調用B類中的who()
方法;如果再去掉B類中的who()
方法,會調用A類中的who()
方法。self::foo()
:執行B類中的foo()
方法(self的用法),B類中沒有foo()
方法,於是繼承了A類的foo()
方法,如果B類中定義了foo()
方法,則執行B類中的foo()
方法;執行A類的foo()
方法,如上.
PHP常見概念混淆(七)之self、static、parent的區別