Расширение класса внешними методами и переменными

fixxxer

К.О.
Партнер клуба
К слову, z-engine позволяет убирать final из классов. Там еще структуры в памяти без очистки между запросами можно объявлять.
"Z-Engine uses FFI to access internal structures of... PHP itself."

Ха, классный трюк! Ну отлично, аргумент про невозможность мокинга final-классов можно считать недействительным :)
 

whirlwind

TDD infected, paranoid
Мда... А я ведь еще помню времена, когда такие вещи называли грязными хаками с негативной коннотацией, а не протаскивали в продукты в качестве фичи.
 

fixxxer

К.О.
Партнер клуба
Для юнит-тестирования подобные хаки - это нормально, тот же PHPUnit из хаков состоит чуть менее чем полностью. Одним больше, одним меньше
 

whirlwind

TDD infected, paranoid
Не провоцируй )))) Тесты надо уметь слушать. Есть запахи тестов, то же самое что запахи кода. Основной признак плохого кода - если вы не можете написать тест в обычных выражениях языка, без привлечения грязных хаков. Тесты - первые пользователи ваших классов. Если для тестирования нужны какие то особые свистелки-перделки, в вашем коде проблемы. И эти же проблемы вылезут у других пользователей классов. А при использовании хаков вы обрекаете ваш код на единственный способ решения проблемы. Все проблемы кода вылазят, когда стремишься к 100% покрытию.
 

fixxxer

К.О.
Партнер клуба
Более-менее весь mocking работает на хаках, и что теперь?

И эти же проблемы вылезут у других пользователей классов.
Это смотря что считать проблемой. Я вот хочу, чтобы пользователи наследовались от абстракции, а не от реализации, ибо нефиг. Проблемой это не считаю. Других проблем не вижу.

Впрочем, когда соблюдается DIP, и с тестированием проблем не возникает. Но в редких частных случаях - когда есть final без абстракции, скажем, domain entity, и надо протестировать какой-нибудь domain service - может быть полезно.
 
Последнее редактирование:

whirlwind

TDD infected, paranoid
Типичное заблуждение, что тестирование = mocking? Многие пишут - не увлекайтесь моками, но не каждый понимает почему. Начнем с того, что если у тебя мок на реализацию, которая от абстракции, то это еще "хуже", чем просто мок, потому что это 99% partial mock. Если этот тест без мока не пишется, то напрямую указывает на проблемы в дизайне. То есть, тут проблема вообще не в моке или final-е. Тот факт, что в некоторых fw есть нативная поддержка моков, сути не меняет. Мок - это способ по месту создать fail-fast реализацию с заданным поведением. Если ты не можешь заменить мок-реализацию на любую другую, то у теста проблемы. И если ты эту проблему решаешь тем, что твой fw может хакнуть ЯП, то эти тесты воняют.
 

fixxxer

К.О.
Партнер клуба
Я про то, что мокинг построен на хаках, а дальше ты сам себе задал вопрос и на него ответил. :)
Тест без моков пишется, со стабами, с анонимными классами даже удобнее стало. Моки зачастую удобнее тем, что позволяют верифицировать поведение, а не состояние (а состояние зависимости волновать как раз не должно). Заменить стабом всегда можно, но не всегда удобно. В тех случаях, когда нельзя - так вообще ничего не получится, хоть стабом, хоть моком, хоть чем, - но они очень редки (domain services те же, которые сами по себе редко используются), и это единственное, когда final у domain entities мешает - вот с этой штукой проблема решается.
Partial mocks вообще ни разу в жизни не делал, не знаю, зачем они могут понадобиться.
 
Последнее редактирование:

Yoskaldyr

"Спамер"
Партнер клуба
@fixxxer мммм..... черная магия....
Хотя уже видел :)))
Первая версия была используя всевозможные хаки php, а вторую уже на z-engine запилил

Конечно лицензия там не очень, да и как-то страшновато в продакшн такое пускать
 

Вурдалак

Продвинутый новичок
Я тут FFI стал изучать, тоже обратил внимание на final и на immutable. С моей точки зрения, это отличные решения, потому что решается чисто техническая задача — mocking/proxying. Я когда-то раньше в старом треде как раз говорил, что было бы круто на уровне reflection этот флаг снимать, чтобы явно в техническом коде можно было творить всю эту грязь.

Единственное, вот неясно не ломает ли это что-то, когда где-то происходит вызов final-метода или PHP не делает таких кросс-файловых оптимизацией , как в C# и прочих нормальных языках?
 

fixxxer

К.О.
Партнер клуба
В PHP все оптимизации на уровне опкод-кэшера (да там даже JIT в 8ке на уровне опкод кэшера), а он работает пофайлово, разве что с preload-ом что-то такое теоретически может быть.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Этим летом я занимался проектом, который изменил мое отношение к final-классам.
Суть в том, что в продуктовом проекте N сотен junior-кодеров, и никто не знал значения "dependency injection", не то что SOLID. Коллективно считалось, что DI - это контейнер, потому что пакет Symfony так называется, пришлось workshop со слайдами сделать.
У меня, конечно, порвало шаблон - нафига задирать ФОТ в несколько раз и кормить несколько офисов народа, но бизнес живет.
Мне надо было отпилить кусок от монолита - показать как это, в принципе, делается без переписывания всего кода.

И вот тут я начал называть классы final. Папка Contracts с интерфейсами, рядом папка Api с классами, которые их реализуют, написал у них в phpdoc @api, а во всех остальных - final с пометкой @internal. Чтобы те, кто захочет расширить реализацию, шли #$% сразу, а если надо менять поведение - правьте код.

Кстати, заметил интересный момент - народ до ужаса боится скопировать код. Даже 10 строк, даже когда разный execution flow и разные типы данных. Причины не знают - суеверный страх, как черных кошек. Говорю, в DRY нет ни слова про код, там про execution flow - стеклянный религиозный взгляд.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
сделали аттрибут #[Immutable]
в принципе, если в SDLC включить статический анализатор - это решает задачу
 

Yoskaldyr

"Спамер"
Партнер клуба
так это уже больше месяца как. Хотя смысла то не много, учитывая что и раньше уже давно были аннотации в пхпдоках
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
это не то же самое, что @psalm-immutable в PHPDoc, это annotation, нарушение которого будет видно в IDE при написании присваивания
 

Yoskaldyr

"Спамер"
Партнер клуба
Я бы даже добавил что @psalm-immutable и @property-read с точки зрения юзер экспириенса чуть лучше чем #[Immutable], т.к. во первых последний в отдельном неймспейсе и внезапно при первом использовании сторм не может найти автодополнение (не знаю почему но не срабатывает), во вторых единообразность оформления и чтения кода - аттрибут не добавляет никакой дополнительной читаемости вместо @psalm-immutable или @property-read. Кстати последний есть в сторме из коробки вообще хз сколько времени.
Так что, пока использовать именно #[\JetBrains\PhpStorm\Immutable] не вижу смысла. А особенно переписывать код с @property-read на него.
 
Сверху