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

时间:2013-10-17 14:11:50

标签: php oop

我无法弄清楚为什么这段代码在PHP中不起作用?

<?php

interface 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)

2 个答案:

答案 0 :(得分:23)

打破SOLID规则。您声明Car::setEngine接受Engine类型的一个参数,但子WaterCar::setEngine接受类型为HydroEngine的参数。即使HydroEngineEngine的子类型,它仍然是不同的类型。

当一个班级Foo implements WaterCar时,这个班级也是instanceof Car。但Foo::setEngine接受HydroEngine,但不接受Engine。所以Foo::setEngine应该implements Car,但不接受Engine类型的参数。打破了Liskov substitution principle。您无法更改子类接口中的参数类型,周期。

继承的关键字是 extends 。子类与父类完全相同,可能更多。它不能比父母更少。由于HydroEngineEngine的专用子类型,这意味着WaterCar 更少而不是Car,因为它只接受更窄Engine的子类型。 E.g:

function (Car $car) {
    $engine = new EngineImplementation;
    $car->setEngine($engine);
}

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

答案 1 :(得分:1)

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

interface WaterCar extends Car {
    function setEngine(Engine $engine);
}