【问题标题】:PHP: Limiting static variable scope to specific classPHP:将静态变量范围限制为特定类
【发布时间】:2012-03-21 08:02:14
【问题描述】:
abstract class Mother {
        protected static $foo = null;
        protected static $bar = null;

        public function getFoo() { return static::$foo; }
        public function getBar() { return static::$bar; }
        public function setFoo($foo) { static::$foo = $foo; }
        public function setBar($bar) { static::$bar = $bar; }
}

class Brother extends Mother {
        protected static $foo = 'BROTHERS';
}

class Sister extends Mother {
        protected static $foo = 'SISTERS';
}

$brother1 = new Brother();
$brother2 = new Brother();
$sister1 = new Sister();
$sister2 = new Sister();

$sister1->setBar('ONLY SISTERS'); // We set $bar = 'ONLY SISTERS' at sister1.
// We want only Sister instances to get this value...
// however Brother instances also get this value!

    echo '<p>Brother 1: Foo="'.$brother1->getFoo().'", Bar="'.$brother1->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
    echo '<p>Brother 2: Foo="'.$brother2->getFoo().'", Bar="'.$brother2->getBar().'"</p>';
// Foo="BROTHERS", Bar="ONLY SISTERS"
    echo '<p>Sister 1: Foo="'.$sister1->getFoo().'", Bar="'.$sister1->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"
    echo '<p>Sister 2: Foo="'.$sister2->getFoo().'", Bar="'.$sister2->getBar().'"</p>';
// Foo="SISTERS", Bar="ONLY SISTERS"

显然,如果 static::$bar 没有在每个孩子(兄弟,姐妹)中明确重新定义,他们的父母(母亲)将为他们设置值(或至少为那些没有重新定义它的人)。

问题:有什么办法可以防止没有重新定义 static::$bar 的孩子接收到新的值?换句话说,如何确保只有被引用的类获得一个新值,即使 static::$bar 没有在每个孩子中显式地重新定义?

【问题讨论】:

  • 我只看到一个选项来实现这一点。您必须覆盖姊妹类中的 getBar 和 setBar 方法。 setBar 方法写入 $this->bar,getBar 检查是否设置了 $this->bar,否则从 parent::$bar 检索。
  • 当你有一个对象实例时,是否有理由让这些静态?
  • @Dan 你可能是对的。另一种选择是在每个孩子中重新声明 static::$bar。问题是没有办法强制程序员这样做。
  • @DaveC 每个对象都将具有相同的值,因此在每个实例中拥有它的副本似乎很浪费。
  • 静态变量(和关联值)的全部目的是跨实例化。

标签: php oop static instance


【解决方案1】:

不,不是你的做法。这就是私有作用域的用途。子类继承所有公共和受保护的静态属性——这意味着它们都指向相同的值,无论它们是父类、子类还是兄弟类。

这是正确且良好的OO。

您应该在父类中将其定义为私有静态变量,然后子类将无法直接看到它,并且可以根据需要创建自己的具有相同名称的私有静态变量。

在您的类中提供静态 getter 和 setter 以访问私有静态属性。

Brother::getFoo();
Sister::getFoo();

您可以将父类 Mother 中的 getFoo() 设为抽象或不抽象,如果您需要直接访问它,请将其设为非抽象,以便您可以这样做:

Mother::getFoo();

【讨论】:

  • 好吧,我认为这是正确的方向,但我需要更多关于如何(以及在​​何处)实现这些功能的详细信息,尤其是 $bar getter/setter,因为我不断收到此错误我尝试的任何事情:致命错误:无法访问属性 Sister::$bar
  • 我应该在每个子类中提供静态getter/setter吗?
  • 你可以在 Mother 类中创建一个,它会通过 Mother::getBar() 访问 Mother::$bar。是的,您需要为所有类实现 getter 和 setter,因为 $bar 是 Mother 私有的。
  • 那没用。它只会为程序员创造毫无意义的工作。
【解决方案2】:

这简直是疯了。

您应该明白extend 定义了IS A 关系。例如:class Duck extends Bird{} 这意味着Duck 的每个实例都是Bird

因此,在您的示例中,每个Brother 都是Mother。我看不出这有什么意义。


还有一件事:你为什么要滥用静态变量?你在那里做的不是面向对象的编程。您只是将全局范围变量和函数包装在命名空间中(恰好看起来像类)。

有关该主题的一些附加链接,您可能会觉得有用:

【讨论】:

  • 所以你认为最好在每个子类中都有一个相同字符串的副本?
  • @user1132363,什么?我在哪里说的?也许你应该了解依赖注入。
  • 嗯,您显然是在暗示我不应该使用静态变量。至少不是我现在这样做的方式 - 但您没有提供任何替代解决方案。
  • 如果你需要一个改变来影响一个对象的多个实例,那么它就是一些外部状态。这意味着,所有对象都包含一个在它们之间共享的实例。了解依赖注入,停止在银盘上索取代码。
  • +1 某处,一颗眼泪刚刚滚落Barbara Liskov's脸颊。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-08
  • 2011-10-17
  • 1970-01-01
相关资源
最近更新 更多