
Комментарии 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)