zoukankan      html  css  js  c++  java
  • PHP静态属性中的子类改变父类、子类改变子类的问题。

    一、静态实例

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

    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的。

  • 相关阅读:
    转:SQL Server 2005 Express附加数据库为“只读”的解决方法!
    通过WPF模拟交通红绿灯(图文教程)
    手把手教你怎样把文件保存到Oracle数据库
    已删除
    JavaScript精炼类(class)、构造函数(constructor)、原型(prototype)
    Ext:RowLayout和ColumnLayout连用必须加panel的问题
    Ext:前台js往gridpanel动态添加记录
    "int i=1" "int i=new int() "和“String str = "a";” “String str = new String("a")”区别以及c#值类型和引用类型
    未能加载文件或程序集“Model Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。系统找不到指定的文件。
    hibernate:inverse、cascade,一对多、多对多详解
  • 原文地址:https://www.cnblogs.com/hxsen/p/13618903.html
Copyright © 2011-2022 走看看