您可以使用不同但"兼容"的签名覆盖接口方法吗?

jzi*_*011 21 php interface phpstorm

考虑以下PHP接口:

interface Item {
    // some methods here
}

interface SuperItem extends Item {
    // some extra methods here, not defined in Item
}

interface Collection {
    public function add(Item $item);
    // more methods here
}

interface SuperCollection extends Collection {
    public function add(SuperItem $item);
    // more methods here that "override" the Collection methods like "add()" does
}
Run Code Online (Sandbox Code Playgroud)

我正在使用PHPStorm,当我这样做时,我在IDE中得到一个错误,基本上说明add()in SuperCollection的定义与它扩展的接口中的定义不兼容,Collection.

在某种程度上,我可以看到这是一个问题,因为该方法的签名与它" 完全覆盖"的签名不匹配.但是,我确实认为这是兼容的,因为SuperItem扩展Item,所以我会看到add(SuperItem)相同的add(Item).

我很好奇这是否支持PHP(版本5.4或更高版本),并且可能IDE有一个错误,无法正确捕获它.

Spu*_*ley 14

不,我非常确定PHP在任何版本中都不支持这一点,而且它宁可打败界面.

接口的关键在于它为您提供了与引用相同接口的其他代码的固定合同.

例如,考虑这样的函数:

function doSomething(Collection $loopMe) { ..... }
Run Code Online (Sandbox Code Playgroud)

此函数期望接收实现该Collection接口的对象.

在函数内,程序员将能够编写对定义的方法的调用Collection,知道该对象将实现这些方法.

如果你有一个像这样的重写接口,那么你有一个问题,因为一个SuperCollection对象可以传递给函数.它会起作用,因为它也是一个Collection由于继承而成的对象.但是,函数中的代码不再能确定它知道add()方法的定义是什么.

根据定义,接口是固定合同.这是不可改变的.

作为替代方案,您可以考虑使用抽象类而不是接口.这将允许您在非严格模式下覆盖,但如果您使用严格模式仍然会出现错误,原因相同.

  • 我不同意这个答案.接口不关心方法定义或其中的关系(例如`add()`一个项目意味着你也可以`delete()`它).他们唯一的责任是强制执行兼容的方法签名(输入/输出).你对他们是固定合同是正确的,但对合同的目的不正确.两个类可以很容易地实现相同的接口并且具有*完全不同的*语义(例如`add()`实际上可以*删除一个类中的*项,只要输入/输出保持相同类型就没关系) . (9认同)
  • @FtDRbwLXw6这是一个解释问题,但我认为接口有责任扩展到函数的语义,而不仅仅是签名。许多著名的 PHP 接口都带有文档块,例如 https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php 或 https://github.com/php-fig/http-message /blob/master/src/RequestInterface.php 。实施者需要阅读文档以确保他们不违反里氏替换原则。这是 PHP 具有名义类型而不是结构类型的优势。 (2认同)