Переопределите параметр метода с помощью дочернего интерфейса в качестве нового параметра
Я не могу понять, почему этот код не работает в 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);
}
?>
Кажется, это не нарушает никаких правил ООП, но почему это дает мне ошибку?
Fatal error: Declaration of WaterCar::setEngine() must be compatible with Car::setEngine(Engine $engine)
2 answers
Это действительно нарушает ТВЕРДЫЕ правила. Вы объявляете 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);
}
Приведенный выше код взорвется, если вы передадите WaterCar
, потому что он не принимает Engine
.
Я думаю, что сигнатура метода все еще должна быть точно такой же, потому что во время компиляции не получается, является ли HydroEngine двигателем.
interface WaterCar extends Car {
function setEngine(Engine $engine);
}