Php 防止/限制方法继承

Php 防止/限制方法继承,php,oop,inheritance,Php,Oop,Inheritance,我有一个应用程序,其中许多对象都在扩展一个抽象类,该类定义了一些方法,如create()edit()retrieve()和delete()。由于每个子类对这些函数使用相同的逻辑,抽象类定义了默认行为,在少数需要扩充的情况下,子类可以重写或使用我内置的钩子 现在我遇到的情况是,一些子类需要设置为不可变的,这意味着它们不应该有edit()或delete()方法。对我来说,这种需求听起来像是一个名为immutable的接口的工作,不可变类可以实现它。问题是接口并没有阻止方法被调用,它们只是强制方法的存

我有一个应用程序,其中许多对象都在扩展一个抽象类,该类定义了一些方法,如
create()
edit()
retrieve()
delete()
。由于每个子类对这些函数使用相同的逻辑,抽象类定义了默认行为,在少数需要扩充的情况下,子类可以重写或使用我内置的钩子

现在我遇到的情况是,一些子类需要设置为不可变的,这意味着它们不应该有
edit()
delete()
方法。对我来说,这种需求听起来像是一个名为
immutable
的接口的工作,不可变类可以实现它。问题是接口并没有阻止方法被调用,它们只是强制方法的存在。所以这显然是行不通的

创建两个父类,一个用于可变对象,另一个用于不可变对象,这很难看,可能会在维护过程中遇到问题。我可以让不可变对象用一个空方法覆盖有问题的方法,这个空方法什么都不做,但这看起来也很混乱,好像我当时没有做正确的OOP


那么,您认为什么是允许一大组类都继承一组方法,但其中一些类不能继承所有方法的最佳方法呢?(所讨论的应用程序是用php编写的,但是任何语言的通用OOP技术都会有所帮助)。

我喜欢Java的方法。抛出异常。创建一个
UnsupportedOperationException
,对于那些不应该使用特定方法的实现,抛出一个,让用户知道他们不能将此功能用于此实现。

创建一个不可变的基类作为基类的子类。 不可变基应该实现对edit()和delete()的重写,这些重写不做任何操作或抛出错误

最后,确保所有不可变的子项都不能编辑或删除

这一战略的好处

  • 通过测试不可变基的实例,轻松检查对象是否不可变

  • 通过修改对象的扩展,可以轻松地将对象从不可变变回不变


另一个我想扔掉的想法是一个可能的解决方案。类可以实现如下所示的接口:

Interface Immutable {
    const immutable = true;
}
然后,基本抽象类可以使用编写
delete()
edit()
方法

if (!$this->immutable) {
    //do_stuff
}

这也可以很好地扩展到类的其他分类,如不可删除和不可编辑,以允许更细粒度的行为。

实际上创建具有空方法或抛出错误的类是不好的-这些方法很混乱,它们占用空间,什么也不做


更好的方法是使不可变类成为基类,并使可变类通过添加修改方法对其进行扩展。这样,每个类只有那些真正属于它们的方法。

这里有一个超短的解决方法,让您的方法成为最终方法,并从以下内容开始:

    if(self::class!=static::class) return;#or throw an error

它不会阻止继承本身,但方法不会在子类中工作(有错误或没有-由您决定)。

从PHP5.4开始,您可以使用

例如,您可以创建一个只包含所有子类所具有的方法的基类:

class EntityManager {
    public function create() {/*...*/}
    public function retrieve() {/*...*/}
}
然后你可以定义几个特征:

trait EditTrait {
    public function edit() {/*...*/}
}

trait DeleteTrait {
    public function delete() {/*...*/}
}
然后创建一个不可变的子类,如下所示:

class LogManager extends EntityManager {
    ...
}
class ContactManager extends EntityManager {
    use EditTrait;
    use DeleteTrait;

    ...
}
还有一个可变的子类,如下所示:

class LogManager extends EntityManager {
    ...
}
class ContactManager extends EntityManager {
    use EditTrait;
    use DeleteTrait;

    ...
}
与其他一些解决方案相比,Traits具有一些优势,例如:

  • 没有代码重复
  • 单一基类
  • 不起作用或没有意义的方法不会出现在不支持它们的类上(对于文档和API尤其重要)

我仍然需要重写
edit()
delete()
方法来抛出异常,对吗?我必须在每一个不可变的类中这样做,这看起来一点也不枯燥。虽然抛出一个异常似乎比仅仅用一个空方法重写更有用,但我必须说,你必须重写这个方法,但我不确定一行异常抛出是否真的违反了任何DRY原则。如果你只是想减少重写次数,你可以简单地创建一个抽象类,抛出适当的异常,你的不可变对象只是简单地扩展它。因此,如果我理解正确,层次结构会是这样的:Base->immutable_Base->immutable_Children和Base->Mutable_Children?在这一点上,我会更好地创建一个可变_基类来放置在基类和可变_子类之间吗?IMHO可变_基类是不必要的,因为可变是基类。然而,这取决于你和你的美感。有些人非常喜欢类树中的对称性。我认为这不是一个好的解决方案。如果有人调用x.delete(y),他/她希望从x(例如,集合)中删除y,而不是什么都没发生。对我来说,问题已经存在于基类中,应该对其进行更改。也许换个名字就够了,明白吗