美文网首页
PHP静态属性中的子类改变父类、子类改变子类的问题。

PHP静态属性中的子类改变父类、子类改变子类的问题。

作者: houxin | 来源:发表于2020-09-08 15:13 被阅读0次

    一、静态实例

    这里我定义了一个如下的类

    class A{
        protected static $instance;
    
        public static function setInstance($ins){
            static::$instance = $ins;
        }
    
        public static function getInstance(){
            return static::$instance;
        }
    }
    class B extends A
    {
    
    }
    
    // 设置值
    B::setInstance('hello');
    
    var_dump(B::getInstance()); echo '<br>';
    var_dump(A::getInstance()); echo '<br>';
    

    这里static::的作用类似于self::,但是是有区别的 。具体差别请自行查询了解。

    你觉的会输出什么?也许你会觉得,第一个输出'hello',第二个应该输出'null'。
    但是,实际输出

    string(5) "hello"
    string(5) "hello"
    

    我们又加一个C类,继承与A类,然后通过C去修改静态变量$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"
    

    此时你是不是已发现,子类改变了父类的值,并改变了和它一起继承的另外的一个子类的值。不知道有没有颠覆你的想象。先提一句,这只是静态属性的问题。具体请往下看。

    二、普通实例

    这次展示下普通实例下的效果

    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
    {
    
    }
    // 设置值
    $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>';
    

    结果如下

    string(5) "hello"
    NULL
    
    string(5) "world"
    NULL
    NULL
    

    这种情况,就比较符合大家的预期。

    三、原因分析

    所以,静态属性的继承跟我们默认想象的不一样哦,尽管我们在子类里可以获取它,可以修改它,但是这个它,指向的都是父类里的那个静态属性。
    确实是子类能改变父类,子类能改变子类。也或者说,所有的父类和子类,都是共享这一个静态属性。
    当然,上面的情况仅发生在你的子类里,没有额外定义一个同名静态属性的情况下。
    如果这样:

    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;
    }
    // 设置值
    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>';
    

    此时打印的结果

    string(5) "hello"
    NULL
    
    string(5) "world"
    string(5) "hello"
    NULL
    

    我们在各个子类内部,定义了一个$instance属性,这时候就是各自是各自的了,不再共享了。

    用处
    很多知名的框架,比如laravel里面大量使用了静态属性,当然也包括静态调用绑定,在查看源码的时候就要注意这一点。父类和子类是不是共享的一个静态属性,子类里面有没有重新定义。子类更改静态属性是否会影响父类吗。最简单直接的就是laravel框架的$app,它是如何保证整个程序那么多个类,在运行的时候都是用的同一个larave例本身的,都是指向同一个$app的。

    相关文章

      网友评论

          本文标题:PHP静态属性中的子类改变父类、子类改变子类的问题。

          本文链接:https://www.haomeiwen.com/subject/pjefektx.html