一、靜態(tài)實例
這里我定義了一個如下的類
class A{
protected static $instance;
public static function setInstance($ins){
static::$instance = $ins;
}
public static function getInstance(){
return static::$instance;
}
}
class B extends A
{
}
// 設(shè)置值
B::setInstance('hello');
var_dump(B::getInstance()); echo '<br>';
var_dump(A::getInstance()); echo '<br>';
這里
static::的作用類似于self::,但是是有區(qū)別的 。具體差別請自行查詢了解。
你覺的會輸出什么?也許你會覺得,第一個輸出'hello',第二個應(yīng)該輸出'null'。
但是,實際輸出
string(5) "hello"
string(5) "hello"
我們又加一個C類,繼承與A類,然后通過C去修改靜態(tài)變量$instance的值。
...
class C extends A
{
}
C::setInstance('world');
var_dump(C::getInstance()); echo '<br>';
var_dump(B::getInstance()); echo '<br>';
var_dump(A::getInstance()); echo '<br>';
此時再打印,你怎么看?可能又要猜錯了。
此時輸出的是
string(5) "world"
string(5) "world"
string(5) "world"
此時你是不是已發(fā)現(xiàn),子類改變了父類的值,并改變了和它一起繼承的另外的一個子類的值。不知道有沒有顛覆你的想象。先提一句,這只是靜態(tài)屬性的問題。具體請往下看。
二、普通實例
這次展示下普通實例下的效果
class A{
protected $instance;
public function setInstance($ins){
$this->instance = $ins;
}
public function getInstance(){
return $this->instance;
}
}
class B extends A
{
}
class C extends A
{
}
// 設(shè)置值
$b = new B;
$b->setInstance('hello');
var_dump($b->getInstance()); echo '<br>';
var_dump((new A)->getInstance()); echo '<br>';
echo '<hr>';
$c = new C;
$c->setInstance('world');
var_dump($c->getInstance()); echo '<br>';
var_dump((new B)->getInstance()); echo '<br>';
var_dump((new A)->getInstance()); echo '<br>';
結(jié)果如下
string(5) "hello"
NULL
string(5) "world"
NULL
NULL
這種情況,就比較符合大家的預(yù)期。
三、原因分析
所以,靜態(tài)屬性的繼承跟我們默認想象的不一樣哦,盡管我們在子類里可以獲取它,可以修改它,但是這個它,指向的都是父類里的那個靜態(tài)屬性。
確實是子類能改變父類,子類能改變子類。也或者說,所有的父類和子類,都是共享這一個靜態(tài)屬性。
當然,上面的情況僅發(fā)生在你的子類里,沒有額外定義一個同名靜態(tài)屬性的情況下。
如果這樣:
class A{
protected static $instance;
public static function setInstance($ins){
static::$instance = $ins;
}
public static function getInstance(){
return static::$instance;
}
}
class B extends A
{
protected static $instance;
}
class C extends A
{
protected static $instance;
}
// 設(shè)置值
B::setInstance('hello');
var_dump(B::getInstance()); echo '<br>';
var_dump(A::getInstance()); echo '<br>';
echo '<hr>';
C::setInstance('world');
var_dump(C::getInstance()); echo '<br>';
var_dump(B::getInstance()); echo '<br>';
var_dump(A::getInstance()); echo '<br>';
此時打印的結(jié)果
string(5) "hello"
NULL
string(5) "world"
string(5) "hello"
NULL
我們在各個子類內(nèi)部,定義了一個$instance屬性,這時候就是各自是各自的了,不再共享了。
用處:
很多知名的框架,比如laravel里面大量使用了靜態(tài)屬性,當然也包括靜態(tài)調(diào)用綁定,在查看源碼的時候就要注意這一點。父類和子類是不是共享的一個靜態(tài)屬性,子類里面有沒有重新定義。子類更改靜態(tài)屬性是否會影響父類嗎。最簡單直接的就是laravel框架的$app,它是如何保證整個程序那么多個類,在運行的時候都是用的同一個larave例本身的,都是指向同一個$app的。