Параметр переопределить метод с дочерним интерфейсом в качестве нового параметра

Я не могу понять, почему этот код не работает в 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)

Solutions Collecting From Web of "Параметр переопределить метод с дочерним интерфейсом в качестве нового параметра"

Он нарушает правила 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); } 

Вышеупомянутый код будет взрываться, если вы WaterCar в WaterCar , потому что он не принимает Engine .

Я думаю, что подпись метода все равно должна быть точно такой же, потому что во время компиляции это не сработает, если HydroEngine – это Двигатель.

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