美文网首页
PHP继承竟然也需要显性基因?

PHP继承竟然也需要显性基因?

作者: 码课sir | 来源:发表于2018-07-31 15:44 被阅读0次

在某一年写某个模块时用到了static成员,在实现子类的过程中发现他们也共享着父类这个成员的值,具体来说就是我在某个子类A中改变了那个成员值,在另外一个子类B使用的时候结果意外的得到了A覆盖后的值。当时以为,原来static成员是在从声明的地方开始的整个类别树中共享的。后来一直隐约记得这个结论,在平常的代码里面更谨慎的使用static成员,除非确认写的类是个独立的工具类,不然不轻易使用static。

直到有一天我的老大跟我商量升级我之前写的一个BaseModel,他无意中问我:好像你不喜欢用static成员?我说没有啊,因为考虑到BaseModel会被经常继承成各种Model,如果我在这里用了static的话,将来容易踩坑。他表示不理解,然后过来与我辩论。我很义正言辞的说明了因为static成员会被共享,如果要调用两个不同的子类的时候,那个static成员的变量的值就会像一个全局变量一样不可控。他不同意。于是本着科学的精神,我们写下了一个简短的代码来验证:

class A {   protected static $var1 = null;   public static function test(){      echo get_called_class().' '.static::$var1.'
';   } } class B extends A {   protected static $var1 = 'b';   } class C extends A {   protected static $var1 = 'c';   } B::test(); C::test(); 

很显然,这次是我败了。我期待的结果是c c,不过其实是b c。那么这样看起来其实子类的static成员是只在子类这一层共享的。但是我总觉得不对劲,明明在写BaseModel的时候我已经又栽过跟头了,为什么这个验证出来并不支持我那个时候遇到的问题呢?于是我发现我记岔了。年轻多好。后来想起来,原来我这里不用static的原因仅仅是因为设计需要。

我以为我错了。直到前几天又写了几个父子类(不是BaseModel了),大胆的用上了static成员,结果是轰轰烈烈的在自测中又摔了一跤。怎么回事!然后我仔细留意了一下自己这次的用法,将上面的例子改了一下运行:

class A {   protected static $var1 = null;   protected static $var2 = null;   public static function test(){      if(!static::$var2){           static::$var2 = static::$var1;      }      echo get_called_class().' '.static::$var2.'
';   } } class B extends A {   protected static $var1 = 'b';   } class C extends A {   protected static $var1 = 'c';   } B::test(); C::test(); 

结果是

B b C b 

如果说上次的结论是对了,那么这次又怎么解释?这里明明就是表示var2是A,B,C共享的。var1和$var2的差别这样看起来仅仅是有声明和没声明的区别。于是我又改成这样:

class A {   protected static $var1 = null;   protected static $var2 = null;   public static function test(){      if(!static::$var2){           static::$var2 = static::$var1;      }      echo get_called_class().' '.static::$var2.'
';   } } class B extends A {   protected static $var1 = 'b';   protected static $var2 = null; } class C extends A {   protected static $var1 = 'c';   protected static $var2 = null; } B::test(); C::test(); 

结果是

B b C c 

我当时内心是崩溃的。于是我上了Stack Overflow,发现栽坑的不止我一个。

只有显式的声明出来的static成员才会被视为是只从属于子类的。

只有显式的声明出来的static成员才会被视为是只从属于子类的。

只有显式的声明出来的static成员才会被视为是只从属于子类的。

重要的事情说三遍!不过如果子类很多的话, 动态决定值的成员 每个都这样去声明,就从写代码这件事上失去了用static的意义。一个更好的方法是,把var2变成一个数组,每个类要用的值放在var[CLASS]里面使用。

不过不管怎么说,如非必要,还是尽量不用static成员继承吧。

还有一个有点类似的“坑”。我们说到private成员的时候,都知道private是指私有的,不会被子类继承。但是有时候写代码的时候会忘记,直到载跟头了才想起来原来是private导致子类找不到该有的成员,或者说是private都在子类声明了,但是因为调用函数时是调用父类函数,结果得到的是父类这个private的值而不是子类的。遇到这种情况不可能又将函数原样的重写在子类里。所以使用private要特别小心。

曾经在使用Rackspace的SDK的时候就看到有些类里面使用了private成员,但是由于他们给出了不必要的打开文件权限,导致代码在我们的服务器上运行不了。那么这个时候本想写个子类覆盖一下这个成员的初始值就好了,结果就因为这是个private成员,而*后需要把所有引用到的地方都拷到自己写的子类里面。为什么我们不直接改SDK,让成员变成protected?因为开发包也许下次就升级了呢?修正之后我们把子类移除就好了。如果修改库代码成了习惯,想升级的时候就没这么欢了。所以说,private成员的使用一定要慎之又慎,如果你也在开发SDK,就更需要考虑使用者是不是需要继承?如果你必须写private,你是不是能够保证代码能够适应各种场景的使用?

除非你有非常充分的理由,static和private都是需要慎重使用的。

相关文章

  • PHP继承竟然也需要显性基因?

    在某一年写某个模块时用到了static成员,在实现子类的过程中发现他们也共享着父类这个成员的值,具体来说就是我在某...

  • 孟德尔遗传的拓展

    等位基因间的相互作用 完全显性(complete dominance)显性等位基因能完全遮盖隐性等位基因的作用,杂...

  • php——接口类

    PHP 接口 PHP 类是单继承,也就是不支持多继承,当一个类需要多个类的功能时,继承就无能为力了,为此 PHP ...

  • 加密猫基因遗传算法

    (1)基因组成:显性和隐性基因 在传统的遗传学中,显性和隐性基因和他们本身的特性有关(比如金色头发是黑头发...

  • 萧峰与郭靖教你学会PHP的Trait

    自PHP5.4之前,PHP面向对象需要复用代码的方式是使用类的继承。但PHP只支持单继承,在应对较复杂的业务逻辑中...

  • 外型那些事

    听闻一些人说像老爹,然后自己和老妈探讨了了一下,得出以下结论: 继承老妈显性基因的地方: 额头 双眼皮 高颧...

  • 在php中extends与implements的区别

    PHP 类是单继承,也就是不支持多继承,当一个类需要多个类的功能时,继承就无能为力了,为此 PHP 引入了类的接口...

  • php——trait

    Trait是自 PHP 5.4.0 起添加的一个新特性,是 PHP 多重继承的一种解决方案。例如,需要同时继承两个...

  • #我们一起读书吧#2019.2.20《基因革命》

    #我们一起读书吧#2019.2.20 今日推荐:《基因革命》 ✨我的收获: 基因不只是显性和隐形;(变异基因表达度...

  • 奥斯卡欠我一座小金人

    见到我的人大多夸我长的漂亮,尤其一双大眼睛,灵动传神。 承蒙双亲优秀的显性基因,我成功地继承了他们并发扬光大了。但...

网友评论

      本文标题:PHP继承竟然也需要显性基因?

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