Комментарии 21
[RFC] Is Literal CheckНа pecl для того же был модуль taint. Идея взята из Перла.
Ну расширить интерфейс можно же
А в чем проблема расширения интерфейса?
`ClassA implements InterfaceA {fun do(object $b){}}`
пример принцип Лисков не нарушает, на сколько я его понимаю
Потому что реализаторы А должны принимать любой инстанс интерфейса Б, а не одну отдельную его реализацию.
Мне кажется, вы не обратили внимание на мой пример. Там нет отдельной реализации интерфейса Б, он заменен на более общий object
, т.о. все клиенты InterfaceA
смогут безболезненно использовать InterfaceB
в качестве аргумента. В свою очередь клиенты ClassA
смогут использовать любой объект
Теперь смотрите. Если в коде есть пример, когда $a1->do(object $c) оно упадет с ошибкой. Но если заменить на $a2 — оно уже не будет падать с ошибкой. В этом и есть нарушение принципа Лисковой. При замене родителя на наследника — код меняет поведение.Это из-за realtime типизации PHP рассуждения «упадёт с ошибкой, не упадёт = поведение». В нормальной типизации $parent->do(object $c) невалиден (с т.з. грамматики то же, что и случайный набор символов) и не запустится, а $child->do(object $c) — валиден. Код валиден или невалиден потому, что не подчиняется принципу Лисков, поведение тут не причем.
С т.з. LSP расширение нормально, подмена касается только сигнатур и должна быть соблюдаться контравариантность в аргументах. Если учесть, что тут замена тут имеет смысл и дело только в сигнатуре do, по-видимому вызывающий код ожидает именно Parent, и использовать объект как Child с его расширенной сигнатурой нельзя.
Дженерики и прочая параметризация тут вторичны.
Contravariance of method arguments in the subtype.Сontravariance:
Preconditions cannot be strengthened in a subtype.
— covariant if it preserves the ordering of types (≤), which orders types from more specific to more generic;
— contravariant if it reverses this ordering;
Из определения следует, что на место родителя мы можем подставить любого наследника. Из определения не следует, что свойства наследника должны повторять свойства родителя. У родителя нет свойства (поведения) do(any $c). У него есть свойствоdo(concrete $c). У наследника оно тоже неявно есть по определению типа, но не только оно. LSP — набор правил для того, чтобы тип можно было заменить подтипом.
Вы своим примером пытаетесь доказать, что если у родителя нет doAny(), то и наследник не должен иметь, потому что $parent->doAny() не компилируется, а такой же $child->doAny() — компилируется.
С точки зрения Лисковой такого ограничения нет. Есть ограничение "Раньше работало и дальше должно продолжать работать"
nikolaposa/rate-limit — Рейт-лимитер общего назначения с бекендом на Redis.
Поправьте, если ошибаюсь, но мне кажется, что алгоритм там наивный, который никак не сглаживает пики нагрузки.
В Yii 3 есть реализация GRCA, предотвращающая пики: https://github.com/yiisoft/yii-web/tree/master/src/RateLimiter
Ну и стоит отметить, что если у вас есть контроль над сервером, нагрузку лучше размазывать средствами Nginx. Там хорошая вариация на тему leaky bucket.
PHP-Дайджест № 176 (11 – 23 марта 2020)