继承子类中的静态属性而不需要重新声明?

发布于 2024-08-31 00:25:34 字数 360 浏览 6 评论 0 原文

我遇到了与 这个人正在写我正在写的应用程序。问题是静态属性不会在子类中继承,因此如果我在主类中使用 static:: 关键字,它也会在我的主类中设置变量。

如果我在子类中重新声明静态变量,它就可以工作,但我希望拥有大量静态属性和子类,并希望避免代码重复。我链接的页面上评分最高的回复有一个指向一些“解决方法”的链接,但似乎有 404 错误。任何人都可以给我一些帮助,或者为我指出上述解决方法的方向吗?

I'm having the same problem as this guy with the application I'm writing right now. The problem is that static properties are not being inherited in subclasses, and so if I use the static:: keyword in my main class, it sets the variable in my main class as well.

It works if I redeclare the static variables in my subclass, but I expect to have a large number of static properties and subclasses and wish to avoid code duplication. The top-rated response on the page I linked has a link to a few "workarounds", but it seems to have 404'd. Can anyone lend me some help or perhaps point me in the direction of said workarounds?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

猫弦 2024-09-07 00:25:34

我不确定它在谈论什么具体的解决方法,我可以想到很多可行的方法。我个人不会在任何代码中使用这些。我建议您看一下 是否可以在 PHP 中过度使用后期静态绑定? 并重新考虑是否有更好的方法来完成您希望完成的任务。

另请记住,我的代码完全未经测试,因为我只是在这里编写的。

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

其他方法都是基于此方法。无论您在何处使用静态属性,都可以插入代码来检测该类并获取它。如果您从未打算在其他地方使用该房产,我只会考虑这一点。

$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;
        }
    }
}

I'm not sure what specific workaround it was talking about, I can think of quite a few that can work. I personally wouldn't use these in any code. I'd recommend you take a look Is it possible to overuse late static binding in PHP? and rethink if there's a better way to do whatever you hope accomplish.

Also keep in mind my code is completely untested as I wrote it just here.

Method 1: Always use an array to figure

All the other methods are based on this one. Whereever you use the static property, you insert the code to detect the class and get it. I would only consider this if you never plan on using the property anywhere else.

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

Method 2: Use a getter/setting methods

If you plan on having it used in more than one spot, this method would be better. Some singleton patterns use a similar method.

<?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;
    }
}

Method 3: __callStatic

This is by far the most convenient method. However you need to have an object instance to use it (__get and __set can't be used statically). It is also slowest the method (much slower than the other two). I'm guessing that since you're already using static properties this is already a non-option. (If this method works for you, it'd be probably be better if you didn't use static properties)

<?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;
        }
    }
}
暗藏城府 2024-09-07 00:25:34

要比 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, ) 

To go a little further than Reece45's answer, you can use the following method to get the value of your array.

<?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, ) 
世界等同你 2024-09-07 00:25:34

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

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

不过,还剩下两个问题:

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

To those that end up here wondering "WTF PHP", it seems there are a couple of reasons for this behavior and why it was kept, albeit weird:

  1. static properties will always use the same memory reference, just like static vars do (source)
  2. that same reference is shared between classes and subclasses (source)
  3. it seems to be useful in some other contexts, so it isn't a "full" bug, just undocumented behavior. If it got "fixed", it would then cause compatibility issues with previously working code (a backwards-compatibility break).

There are two questions left, though:

  • why wouldn't late static bindings change that: probably related to #1
  • why that drawback we see isn't explained in the doc pages................ Well, that's PHP, right?
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文