一信卡、靜態(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)屬性的繼承跟我們默認(rèn)想象的不一樣哦,盡管我們在子類里可以獲取它失息,可以修改它譬淳,但是這個它,指向的都是父類里的那個靜態(tài)屬性根时。
確實是子類能改變父類瘦赫,子類能改變子類。也或者說蛤迎,所有的父類和子類,都是共享這一個靜態(tài)屬性含友。
當(dāng)然替裆,上面的情況僅發(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)屬性儿咱,當(dāng)然也包括靜態(tài)調(diào)用綁定庭砍,在查看源碼的時候就要注意這一點。父類和子類是不是共享的一個靜態(tài)屬性混埠,子類里面有沒有重新定義怠缸。子類更改靜態(tài)屬性是否會影響父類嗎。最簡單直接的就是laravel框架的$app
钳宪,它是如何保證整個程序那么多個類揭北,在運(yùn)行的時候都是用的同一個larave例本身的扳炬,都是指向同一個$app的。