PHP靜態(tài)屬性中的子類改變父類、子類改變子類的問題。

一、靜態(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的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容