强制覆盖父类方法PHP

时间:2015-01-06 16:15:03

标签: php class inheritance interface

我有一种情况,即尽管有相当多的谷歌搜索/搜索,似乎逃脱了我。简而言之,这就是问题所在:

情况

PHP 5.3+(但尚未具体 - 我实际上运行的是5.5 / 6,但环境的目标是灵活)。

我试图编写一个可以迫使其他开发人员进行最佳实践的可靠实现。

我有一个父类:

class A {
    public function doSomething() {
        // does something
    }
}

标准用例是使用A::doSomething

在特殊情况下,需要扩展名。

class B extends A {
    public function doSomething() {
        // does something .. AND
        $this->doSomethingElse()
    }

    private function doSomethingElse() {
        // does something else
    }
}

如果我想做某事,那么我可以A::doSomething 如果我想做某事并做其他事情,那么我可以B::doSomething

为了使让其他开发人员适应最佳实践,我已经实现了一个接口:

interface C {

    public function doSomething() {
        // does something else
    }

    public function doSomethingElse() {
        // does something else
    }
}

B类然后实现接口C.听起来很简单?

class B implements C {
    public function doSomething() {
        // does something .. AND
        $this->doSomethingElse()
    }

    private function doSomethingElse() {
        // does something else
    }
}

我不想假设孩子B实施CA扩展到E可能有一些完全正当的理由,其中E不想实施C

我的实际问题:

如果我执行以下操作,并且未实施doSomething方法,则以下内容没有错误:

class B implements C {
    private function doSomethingElse() {
        // does something else
    }
}

..正如你所期望的那样; AdoSomething提供了B来满足C的要求。

问题是这会让某人编写一个不能抛出错误的不完整方法。在上述情况下,B::doSomething不会调用B::doSomethingElse

方法,接口(或类似技术)是否有可能要求子项在当前继承级别实现方法

当然我可以写笔记,文档等......但界面的重点是让人们正确地做到这一点!

其他提出类似问题的人要么(有时可以理解)被误解股票回答是"架构错了" ......我和#39 ; d喜欢挑战,如下例所示:

以下是真实世界项目的示例:

  • A =商品待售:ShopItem
  • B =商品类型"啤酒" :啤酒
  • C = BoozeInterface:说明触发ID要求的接口
  • D =类型"蔬菜"的商品项目:蔬菜

A可能有一个名为... A::attemptToBuy的方法 C会强制执行ID所需的方法。

BeerVegetable都是ShopItem的类型 这是标准的逻辑继承。

Beer需要使用BoozeInterface(或任何合适的内容)。对于WineSpirit等尚未实施但未来可能的要求也是如此。

某些项目完全适合通用ShopItem类。他们不需要额外的功能。 ShopItem::attemptToBuy是一个正常的用例。

然而 - 我必须依赖有人记得覆盖Wine::attemptToBuySpirit::attemptToBuy

正如您所看到的 - 如果我想真的将其锁定,我理想情况下可以强制覆盖当前的继承级别。
(我确定有更好的例子,但我已尽力使其尽可能明显。)

我很高兴,如果答案是"不,你不能这样做" ...我只是想知道你是否可以。我有代码工作,但只是通过非强制的直接覆盖。但我希望它被迫!

提前致谢。 瑞克

2 个答案:

答案 0 :(得分:1)

为什么不将A类抽象化并以这种方式使用这些方法:

abstract class A
{
    abstract protected function doSomething() {}
    abstract protected function doSomethingElse() {}
}

现在任何扩展A类的类都必须定义这两个方法。

干杯!

答案 1 :(得分:0)

我认为您正在倒退 - 我不确定您是否希望在客户端 - 开发人员创建的子类中强制执行覆盖(使用抽象方法轻松完成),您希望提供在您提供的抽象类中重写不能的方法,以确保它能达到您想要的效果?

如果您提供抽象类ShopItemBoozeItem,那么:

<?php

// base ShopItem with default `attemptToBuy` functionality
abstract class ShopItem {

    public function attemptToBuy() {
        echo "buying ShopItem";
    }
}

// Booze sub-class, with an override on `attemptToBuy` 
// (e.g. applying age restrictions check)
abstract class BoozeItem extends ShopItem {

    final public function attemptToBuy() {
        echo "buying BoozeItem";
    }
}

?>

客户端开发人员可以愉快地创建扩展Beer子类的BoozeItem类。

<?php

class Beer extends BoozeItem { }

$oBevvy = new Beer();
$oBevvy->attemptToBuy();

?>

输出:购买BoozeItem

由于BoozeItem::attemptToBuy()已声明为final,因此无法被Booze::attemptToBuy()覆盖(尝试创建该方法会导致错误) - 因此您的对象功能已被锁定

Beer可以扩展到LagerAle(例如),这些会从attemptToBuy()继承BoozeItem(因为Beer延伸BoozeItem他们不会被允许覆盖该方法,因为它已声明final - 它只是被定义的继承行为。这不是你想要的,但它可能是我认为最接近的。