Трейты: польза и вред
Вопрос
Когда вы используете трейты, а когда предпочитаете композицию?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Трейт копирует код в класс, это не тип и не зависимость
Хорошо для мелкой сквозной функциональности без состояния или с простым состоянием
Плохо: скрытые зависимости, конфликты имён, неявное состояние, сложно тестировать изолированно
Композиция через внедрённый сервис явнее и подменяется в тестах
Абстрактные методы в трейте как контракт для класса
Примеры: SoftDeletes, Notifiable в Laravel
Что могут спросить следом
- Как протестировать трейт?
- Что будет, если два трейта объявят одинаковое свойство?
Разбор
Трейт это копирование кода в класс на этапе компиляции. Он удобен для небольшой сквозной функциональности, которую нужно добавить многим классам, но которая не тянет на отдельную иерархию: временные метки, мягкое удаление, генерация slug. В Laravel так сделаны SoftDeletes, HasFactory, Notifiable.
Минусы начинаются, когда трейт обрастает логикой. Он неявно требует от класса свойства или методы, тянет зависимости через статические вызовы или фасады, конфликтует по именам с другими трейтами. Трейт нельзя подменить в тесте и нельзя использовать как тип.
Поэтому для бизнес-логики выбираю композицию: отдельный сервис внедряется через конструктор, его видно в сигнатуре, и в тесте его легко подменить. Если трейт всё-таки нужен, объявляю в нём абстрактные методы, которые класс обязан реализовать: так зависимость становится явной. А тестирую трейт через анонимный класс, который его использует.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Ещё по теме «ООП, трейты и интерфейсы»
- Абстрактный класс или интерфейс в PHP
- Поверхностное клонирование
- Продвижение свойств в конструкторе
- Класс с интерфейсом и наследованием
- final и видимость констант
- Диспетчер событий с приоритетами
- Склад с исключениями предметной области
- Фигуры через интерфейс и абстрактный класс