为了账号安全,请及时绑定邮箱和手机立即绑定

用子接口作为新参数覆盖方法参数

用子接口作为新参数覆盖方法参数

PHP
海绵宝宝撒 2019-11-04 13:59:20
我不知道为什么此代码在PHP中不起作用?<?phpinterface Engine {    function run();}interface HydroEngine extends Engine {    function run();}interface Car {    function setEngine(Engine $engine);}interface WaterCar extends Car {    function setEngine(HydroEngine $engine);}?>看来它没有违反任何OOP规则,但是为什么它给我一个错误?Fatal error: Declaration of WaterCar::setEngine() must be compatible with Car::setEngine(Engine $engine)
查看完整描述

3 回答

?
莫回无

TA贡献1865条经验 获得超7个赞

它确实违反了SOLID规则。您声明Car::setEngine接受一个类型的参数Engine,但子级WaterCar::setEngine接受一个类型的参数HydroEngine。即使HydroEngine是的子类型Engine,它仍然是不同的类型。


当上课的时候Foo implements WaterCar,上课也是正确的instanceof Car。但是Foo::setEngine接受一个HydroEngine,但是不接受一个Engine。因此,Foo::setEngine据推测implements Car,但不接受type参数Engine。这打破了Liskov替代原则。您不能在子接口,周期中更改参数的类型。


继承的关键字是明确的extends。子类与父类完全相同,甚至可能更多。它不能做的比父项少。既然HydroEngine是一个专门亚型Engine,这将意味着一个WaterCar不小于比Car,因为它只接受的更窄的亚型Engine。例如:


function (Car $car) {

    $engine = new EngineImplementation;

    $car->setEngine($engine);

}

如果您传入,则上面的代码会崩溃WaterCar,因为它不接受Engine。


查看完整回答
反对 回复 2019-11-04
?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

我认为方法签名仍然需要完全相同,因为在编译时,如果HydroEngine是Engine,则无法解决。


interface WaterCar extends Car {

    function setEngine(Engine $engine);

}


查看完整回答
反对 回复 2019-11-04
?
万千封印

TA贡献1891条经验 获得超3个赞

考虑一个实例$wc,该实例实现WaterCar并传递给期望实现的函数/方法Engine。它通过测试对象instanceof(Engine),然后将a传递IonEngine给水车实例... boom。我知道埃菲尔是唯一允许协变重新定义的语言。

查看完整回答
反对 回复 2019-11-04
  • 3 回答
  • 0 关注
  • 346 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信