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

ple*_*ock 15 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);
}

?>
Run Code Online (Sandbox Code Playgroud)

它似乎没有打破任何OOP规则,但为什么它给我一个错误?

Fatal error: Declaration of WaterCar::setEngine() must be compatible with Car::setEngine(Engine $engine)

dec*_*eze 23

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

当一个班级时Foo implements WaterCar,这个班级也是如此instanceof Car.但Foo::setEngine接受了HydroEngine,但不接受Engine.所以Foo::setEngine据说implements Car,但不接受类型的参数Engine.这打破了利斯科夫替代原则.您无法更改子类接口中的参数类型.

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

function (Car $car) {
    $engine = new EngineImplementation;
    $car->setEngine($engine);
}
Run Code Online (Sandbox Code Playgroud)

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