我最近注意到,在某些情况下我真正喜欢做的事情(调用super)是一个反模式。(http://en.wikipedia.org/wiki/Call_super)
我的问题是:
如何做以下事情(我们大多数人都需要的基本事情,为对象添加一些细节)。我将在对象var:
中为数组添加一个新元素 <?php
class A {
// bla bla bla
public function __construct() {
$this->_data['newDetail'] = "Ipiicaei";
}
}
class B extends A {
// bla bla bla
// Override constructor, I need to add one more detail for this class
public function __construct() {
parent::__construct();
$this->_data['newDetailSubcls'] = "Something";
}
}
现在…如果我不调用父类构造函数来添加第一个元素,我有两种可能:
在每个子类中添加父类通常执行的部分代码,并将其从父类中删除。因此,如果我用999个类扩展它,我将在parent中复制999*行。
从父类调用在子类中实现的方法(模板方法模式,他们推荐的)。因此,如果我只需要一个类来添加它,并且998的其余部分的行为与父类完全相同,则在每个类中添加一个空函数。
请记住,我的例子是简单的(这是一个例子应该如何),但父类和/或子类可能会做复杂的事情。
我可以理解为什么在某些情况下调用super可能是不好的。但我觉得这个还行。
所以…你会怎么接近?忽略call super是一个反模式,并按照我的做法(或者如果我的方式不好,过去会这样做)?还是……如何?
使用构造函数是这种反模式出现的一个不好的例子,因为在PHP中,就像在大多数支持继承的语言中一样,
如果子类没有定义构造函数,那么它可以像普通的类方法一样从父类继承…(来自PHP手册).
如果在您试图定义的其他998个类中的任何一个中故意不包含构造函数,则基构造函数将被调用,这几乎要求在每个派生类上添加构造函数以避免此功能。这就是为什么不建议在构造函数中添加可能改变受保护字段/属性状态的逻辑,或者调用可能在派生类中被覆盖的虚方法。
然而,反模式实际上表示:请注意,调用父元素的要求是反模式(来自维基百科)
所以,调用方法的基类版本是可以的,只要派生类不要求调用方法的基类版本。派生类必须行为正确,即使基方法从未被调用。这将避免这样一种情况:派生类覆盖了虚拟方法,但没有实现某些特殊要求(可能是因为缺乏基类的文档),此时派生类的行为不符合系统的预期,可能导致系统崩溃或意外行为,这是典型的违反Liskov替代原则的情况。
在您的特定示例中,此反模式不适用:您正在扩展构造函数,根据定义,当它们将类实例化为有用状态时需要调用构造函数。在大多数情况下,这就是你想要的。