Какие минусы использования магических методов в PHP
Что проверяют
Понимаете ли вы, какую цену платите за гибкость __get, __set, __call и __callStatic, и умеете ли жить с ней в реальных фреймворках. Следом обычно спрашивают, где магия всё-таки оправдана и чем её заменить в современном PHP.
Как отвечать
Коротко назовите, о чём речь: методы, которые PHP вызывает сам при обращении к недоступному свойству или методу (__get, __set, __isset, __unset, __call, __callStatic). Минусы:
- статический анализ слепнет: PHPStan, Psalm и IDE не знают о свойствах и методах, которых нет в классе. Приходится поддерживать
@propertyи@methodв PHPDoc, а для Laravel генерировать их через IDE Helper; - опечатки не ловятся:
$user->emialуйдёт в__getи обычно вернётnullвместо ошибки, баг всплывёт далеко от места; - нарушение инкапсуляции:
__getсрабатывает и наprivate/protectedсвойства при обращении снаружи, так что закрытое поле внезапно читается; - сюрпризы с массивами:
$obj->items[] = 1через__getменяет копию и даёт notice «Indirect modification of overloaded property», если метод не возвращает ссылку; - проверки врут:
method_exists()для метода из__callвернётfalse, аis_callable()вернётtrue; - производительность: каждое обращение это вызов функции. В обычном коде разница незаметна, в горячих циклах по тысячам объектов уже видна.
Где оправдано: прокси, ленивая загрузка в ORM, фасады Laravel на __callStatic. Альтернативы: явные геттеры, readonly-свойства, а с PHP 8.4 хуки свойств, которые дают вычисляемые свойства без магии и видны анализаторам.
Где спотыкаются
Называют все методы с двойным подчёркиванием одинаково вредными. __construct и __invoke проблем не создают, вопрос именно в перехвате обращений.
Считают производительность главным минусом. Реальная боль в том, что код нельзя проверить до запуска.
Не знают, что в PHP 8.2 динамические свойства объявлены устаревшими, и путают это с __set: класс с __set предупреждение не получает, а обычный класс без #[AllowDynamicProperties] получает.