Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Почему нарушения LSP в PHP иногда фатальные, а иногда и предупреждения?

Автор вопроса: bishopОтветов: 2

Это нарушение LSP вызывает фатальную ошибку:

abstract class AbstractService { }
abstract class AbstractFactory { abstract function make(AbstractService $s); }
class ConcreteService extends AbstractService { }
class ConcreteFactory extends AbstractFactory { function make(ConcreteService $s) {} }

Это нарушение LSP также вызывает фатальную ошибку:

interface AbstractService { }
interface AbstractFactory { function make(AbstractService $s); }
class ConcreteService implements AbstractService { }
class ConcreteFactory implements AbstractFactory { function make(ConcreteService $s) {} }

Хотя это нарушение LSP вызывает только Предупреждение:

class Service { }
class Factory { function make(Service $s) {} }
class MyService extends Service { }
class MyFactory extends Factory { function make(MyService $s) {} }

Почему? Разве они не должны быть фатальными, поскольку все они контравариантны?

phpliskov-substitution-principle

Ответы

Ответ 1 · рейтинг 8 · jszobody

В первом случае это фатальная ошибка, поскольку PHP требует совместимости с родительский абстрактный класс:

При наследовании от абстрактного класса... сигнатуры методов должны совпадать.

то же верно во втором случае:

Класс, реализующий интерфейс, должен использовать точно такие же сигнатуры методов, которые определены в интерфейсе. Если этого не сделать, произойдет фатальная ошибка.

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

Это, очевидно, не очень хорошая практика и, как вы указываете, нарушает LSP. Это всего лишь один из многих способов, которыми PHP дает вам острые предметы и позволяет вам пораниться, если вы не будете осторожны. знак равно

Если вы хотите, чтобы LSP применялся, вам нужно использовать интерфейс, абстрагироваться или сделать свой метод final в родительском классе.

Вот пример final: https://3v4l.org/s42XG

Ответ 2 · bishop

В мае 2019 г. RFC об ошибках LSP был обновлен язык. Начиная с PHP 8, механизм всегда генерирует фатальную ошибку для несовместимых сигнатур методов.

До этого изменения производный класс мог волей-неволей изменить сигнатуру, проигнорировать ошибку и двигаться дальше. Больше ничего: классы, как и abstract class и interface, должны соблюдать LSP.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы