Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
让PHP子类继承静态属性的单独实例_Php_Oop_Inheritance - Fatal编程技术网

让PHP子类继承静态属性的单独实例

让PHP子类继承静态属性的单独实例,php,oop,inheritance,Php,Oop,Inheritance,标题可能不太清楚,下面是一个例子 abstract Class A { public static $property = null; } Class B extends A { } Class C extends A { } 我希望在扩展的所有类中都有一个“None”方法,这个方法应该返回一个被调用类的实例(总是相同的)。因此: B::None() // Returns a "default" B C::None() // Returns a "default" C 这

标题可能不太清楚,下面是一个例子

abstract Class A {
    public static $property = null;
}

Class B extends A {

}

Class C extends A {

}
我希望在扩展的所有类中都有一个“None”方法,这个方法应该返回一个被调用类的实例(总是相同的)。因此:

B::None()  // Returns a "default" B
C::None()  // Returns a "default" C
这是为什么:我有(简化)几个时段,可以分配给或不分配给几种类型的活动。所以我可以有一个冲浪的位置和一个游泳的位置。该插槽可能为空。在我的代码中,当报告时,我当然可以这样做

if (Slot.Surfing == null) {
    println "Not surfing anywhere";
} else {
    println Slot.Surfing.Location;
}
但我不想检查,只想写信

println Slot.Surfing.Location;
并将插槽预先分配给Surfing::None()。实际上,我会在一个超类中这样做,并让它自动分配None的“适当”实例

这样一来,Slot.Surfing(无处)和Slot.swing(无处)就不同了,但对我来说,这实际上是一个特性

问题是,如果我真的想检查我在哪里游泳,我必须确定

if (Slot.Surfing == Surfing::None()) {
工作。为此,None()必须始终返回相同的对象。我可以在冲浪的某个字段上运行检查,可能是一个非i18n-ed整数值。。。0或-1是典型的选择。。。但为此目的增加一个属性似乎设计得不好

注意:这与Singleton(anti)模式有许多相似之处,但实际上它不是Singleton(见底部)

但是,如果我在A中实现
None()
方法,我必须处理这样一个事实:任何静态属性在A中只“存在”一次,而不是在每个子类中。因此,我创建了一个默认的B实例,将其保存在a中,然后对a的其他子类的所有后续调用都将找到并返回该实例,
C::None()
将是B的实例

我可以让None()方法每次都创建一个新的默认实例。这是可行的,但现在我有几个“默认”B,在某些情况下,两个属性都设置为
B::None()
将被正确地认为是不同的

最后,我提出了这个解决方案(PHP5.3.+):

我在堆栈溢出和其他地方进行了检查,并采用了相同的方法(注意
$instance
数组在被调用类的名称上索引):

然而,也许是因为我还是一个湿漉漉的人,对我来说,这种方法很难闻。我认为应该有一种方法在父类中声明一个子静态属性,并从超类访问它(当然,然后我会问自己:如果a声明一个“下游”静态属性,B从a继承,C从B继承,那么该属性现在存在于何处,或者应该存在于何处?--我没有满意的答案)

增编-单身人士 上述方法在实践中与
单例
没有太大区别。(多亏Touki给我指出了这一点)我可以通过依赖注入摆脱单身。然而,在这种情况下,它需要传递,比如说,
None\u C
给所有可能需要默认值作为对C实例的引用的方法。然后,我必须将
None\u C
推到我的
配置
对象中,让它知道我可能声明的a的任何子类。乍一看,这味道更重(尽管事实上,添加A的另一个子类相当于更改系统的配置…这将是更改
配置的原因)

TL;博士 因此,长话短说,假设上述方法确实有效

  • 从OOP的角度来看,让父类维护其“活动”子类的静态数组是否可以接受
  • 有更好和/或更干净的方法吗

如果内存不是一个问题(现在很少是这样),那么解决方案就是进一步进入OOP领域

真正需要“独生子女”的问题是,我希望比较是可靠的。当然,两个不同的“空”对象虽然都是“空”的,因此在这方面是相同的,但它们不是同一个对象。如果它们也有相同的属性,那么
=
操作符将返回TRUE,但是如果其中一个属性由于某种原因(例如,由于错误)而发生轻微更改,
=
将返回FALSE。在单例上下文中使用
==
PHP5操作符可以解决这个问题,但会引入更多的复杂性

简单的解决方案(对我来说不是很明显)是完全放弃比较,简单地替换:

if (Slot->Surfing == Surfing::None())
以适当的方式

Slot->Surfing->isNull() // or maybe isEmpty() depending on semantics
然后我可以在父类中声明isEmpty方法,这表明我确实还需要一个更具体的比较运算符:

abstract Class A {
    ...
    public static function createNull() {
        $nulled = new A();
        $nulled->setNull();     // Whatever is needed to nullify an object
        return $nulled;
    }

    public function setNull() {
        $this->nullFlag = true; // Example
        return $this;
    }

    public function isNull() {
        return (true === ($this->nullFlag)); // Or whatever else
    }
    
    abstract function equals($obj);
    abstract function compareTo($obj);
}

Class Surfing extends A {
    public function equals($obj) {
        if (null == $obj) {
            return false;
        }
        if ($this === $obj) {
            return true;
        }
        if (!($obj instanceOf Surfing)) {
            return false;
        }
        // Properties
        foreach(array('property1','property2',...) as $val) {
            if ($this->$val !== $obj->$val) {
                return false;
        }
        // Maybe some other check
        ...
        return true;
    }
}

...

Slot->Surfing = Surfing::createNull();

...

if (Slot->Surfing->isNull()) {
    ...
}

这种方法的另一大优点是,现在每个活动都是一个独立的对象,可以在不改变其他实例的情况下安全地进行更新(如果
Slot->Surfing
是一个空对象,要将它设置为我需要重新分配的其他对象,我不能简单地继续修改它——这实际上引入了可怕的耦合,并极有可能产生微妙的bug).

您是否检查了-aka使用
static::
关键字而不是
self::
单例不是从“面向对象的角度”来看的@VladPreda,是的,我做了,但它不起作用-我仍然是指a:::$none属性的一个全局实例。@Touki,我本来想说这是一个经典模式,但在阅读你们的链接时,我发现只有Erich Gamma怀疑它。我会研究这个依赖性的东西。即使它可能不会成功,我的感谢你已经很好地描述了你所做的尝试,但没有在更大的范围内实际如何使用它。如果没有这些,就很难给出正确的建议。
Slot->Surfing->isNull() // or maybe isEmpty() depending on semantics
abstract Class A {
    ...
    public static function createNull() {
        $nulled = new A();
        $nulled->setNull();     // Whatever is needed to nullify an object
        return $nulled;
    }

    public function setNull() {
        $this->nullFlag = true; // Example
        return $this;
    }

    public function isNull() {
        return (true === ($this->nullFlag)); // Or whatever else
    }
    
    abstract function equals($obj);
    abstract function compareTo($obj);
}

Class Surfing extends A {
    public function equals($obj) {
        if (null == $obj) {
            return false;
        }
        if ($this === $obj) {
            return true;
        }
        if (!($obj instanceOf Surfing)) {
            return false;
        }
        // Properties
        foreach(array('property1','property2',...) as $val) {
            if ($this->$val !== $obj->$val) {
                return false;
        }
        // Maybe some other check
        ...
        return true;
    }
}

...

Slot->Surfing = Surfing::createNull();

...

if (Slot->Surfing->isNull()) {
    ...
}