在没有重新声明的情况下继承子类中的静态属性?

时间:2010-05-01 22:11:16

标签: php inheritance static late-static-binding

我和我正在编写的应用程序有this guy相同的问题。问题是静态属性不是在子类中继承的,所以如果我在我的主类中使用static ::关键字,它也会在我的主类中设置变量。

如果我重新声明我的子类中的静态变量,它可以工作,但我希望有大量的静态属性和子类,并希望避免代码重复。我链接的页面上排名靠前的响应有一些指向“解决方法”的链接,但它似乎有404个。任何人都可以借给我一些帮助,或者让我指出所说的解决方法吗?

3 个答案:

答案 0 :(得分:6)

我不确定它在谈论什么具体的解决方法,我可以想到很多可行的方法。我个人不会在任何代码中使用这些。我建议你看看Is it possible to overuse late static binding in PHP?并重新考虑是否有更好的方法来做任何你希望完成的事情。

另外请记住,我的代码完全未经测试,就像我在这里写的那样。

方法1:始终使用数组来计算

所有其他方法都基于此。无论您使用静态属性,都可以插入代码来检测类并获取它。如果您从未计划在其他任何地方使用该物业,我只会考虑这一点。

$class = get_called_class();
if(isset(self::$_names[$class])) {
    return self::$_names[$class];
}
else {
    return static::NAME_DEFAULT;
}

方法2:使用getter / setting方法

如果您打算在不止一个地方使用它,这种方法会更好。一些单例模式使用类似的方法。

<?php
class SomeParent {
    const NAME_DEFAULT = 'Whatever defaults here';

    private static $_names = array();

    static function getName($property) {
        $class = get_called_class();
        if(isset(self::$_names[$class])) {
            $name self::$_names[$class];
        }
        else {
            $name = "Kandy"; // use some sort of default value
        }
    }

    static function setName($value) {
        $class = get_called_class();
        self::$_names[$class] = $value;
    }
}

方法3:__ callStatic

这是迄今为止最方便的方法。但是,您需要有一个对象实例才能使用它(__get和__set不能静态使用)。它也是最慢的方法(比其他两个慢得多)。我猜测,因为你已经在使用静态属性,所以这已经是一个非选择。 (如果这种方法适合你,那么如果不使用静态属性可能会更好)

<?php
class SomeParent {

    const NAME_DEFAULT = 'Whatever defaults here';

    private static $_names = array();

    function __get($property) {
        if($property == 'name') {
            $class = get_called_class();
            if(isset(self::$_names[$class])) {
                return self::$_names[$class];
            }
            else {
                return static::NAME_DEFAULT;
            }
        }
        // should probably trigger some sort of error here
    }

    function __set($property, $value) {
        if($property == 'name') {
            $class = get_called_class();
            self::$_names[$class] = $value;
        }
        else {
            static::$property = $value;
        }
    }
}

答案 1 :(得分:0)

要比Reece45的答案更进一步,您可以使用以下方法获取数组的值。

<?php
class MyParent {
    public static $config = array('a' => 1, 'b' => 2);

    public static function getConfig() {
        $ret = array();
        $c = get_called_class();
        do {
            $ret = array_merge($c::$config, $ret);
        } while(($c = get_parent_class($c)) !== false);
        return $ret;
    }
}

class MyChild extends MyParent {
    public static $config = array('a' => 5, 'c' => 3, 'd' => 4);
    public function myMethod($config) {
        $config = array_merge(self::getConfig(), $config);
    }
}

class SubChild extends MyChild {
    public static $config = array('e' => 7);
}

var_export(MyChild::getConfig());
// result: array ( 'a' => 5, 'b' => 2, 'c' => 3, 'd' => 4, )

$mc = new MyChild();
var_export($mc->myMethod(array('b' => 6)));
// result: array ( 'a' => 5, 'b' => 6, 'c' => 3, 'd' => 4, )

var_export(SubChild::getConfig());
// result: array ( 'a' => 5, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 7, ) 

答案 2 :(得分:0)

对于那些最终想知道“WTF PHP”的人来说,这种行为似乎有几个原因以及为什么保留它,尽管很奇怪:

  1. 静态属性将始终使用相同的内存引用,就像静态变量一样 (source)
  2. 在类和子类之间共享相同的引用 (source)
  3. 它似乎在 some other contexts 中很有用,因此它不是“完整”错误,只是未记录的行为。如果它得到“修复”,则会导致与以前工作代码的兼容性问题(向后兼容性中断)。

还有两个问题:

  • 为什么后期静态绑定不会改变这一点:可能与 #1 相关
  • 为什么我们看到的这个缺点没有在文档页面中解释......嗯,那是 PHP,对吧?