Источник (1)

Вопрос прозвучал на ~ 30й минуте видео:

https://youtu.be/9aGv-ylsYDI

Источник (2)

В конце прошлого года перед релизом PHP 8 ведущие разработчики языка высказались про неудачную реализацию трейтов в PHP. А после прошел интересный батл «Трейты в PHP — зло?».

Мы относимся к написанию и использованию собственных трейтов с большой осторожностью, стараясь их избегать. И вот несколько причин:
(минус) трейты могут увеличивать связанность (coupling) вашего кода;
(звезда) частично решают проблему переиспользования типового инфраструктурного или обслуживающего кода, при этом несут опасность накопления бизнес-логики в руках новичка;
(минус) трейты фактически не определяют структуру и не являются типом, но при этом позволяют применять внутри своих методов конструкции ООП.

Например, вызов конструктора или обращения к контексту $this. При этом разработчик не может гарантировать, что поведение класса, к которому будет подключен трейт, совпадет с ожидаемым поведением логики работы методов трейта.

Источник (3)

— Что не так с трейтами?

— Как и любой инструмент, трейт должен быть в арсенале разработчика. Но стоит использовать его правильно: например, для шаринга каких-то методов-хелперов между несвязанными классами в библиотеках, где мы хотим дать пользователям возможность расширять функционал без наследования или DI.

Конечно трейты могут стать «leaky». И чтобы не выстрелить себе в ногу, я для себя выделил три правила:

Для любого трейта должен быть соответствующий интерфейс.

Трейт должен быть полностью самодостаточным: всё, что он использует, должно быть объявлено внутри него самого.

Трейты должны быть как можно меньше. В идеале один метод — один трейт.

Источник (4) ~ Перевод статьи о трейтах

Предстоящий выпуск PHP 5.4.0 включает в себя множество новых функций, в том числе Traits. Хотя я считаю, что это отличная функция с большими возможностями, я также боюсь, что она может попасть в категорию часто используемых функций, таких как eval(), goto, константы, оператор @, наследование классов и регулярные выражения.

Что такое трейты?

Здесь мы можем говорить о двух разных вещах. Истинное определение Trait — это единица поведения (что в основном означает набор простых методов). Это отличается от концепции Mixin / Примесей, которая добавляет состояние к определению трейта. Это означает, что все трейты являются примесями, но трейтами могут быть только примеси, у которых нет состояния. Следовательно, трейты — это не что иное, как подмножество примесей.

Думайте об этом как о целочисленном типе и типе с плавающей запятой (в PHP). Все значения int могут быть точно представлены как значения с плавающей запятой. Но подавляющее большинство значений с плавающей запятой не могут быть выражены точно как значение типа int.

Я упоминаю об этом потому, что то, что в настоящее время реализовано в PHP 5.4, на самом деле является примесью. Это называется трейтом, но реализация поддерживает состояние, поэтому на самом деле это примесь. Я поднимаю этот вопрос, потому что это (на мой взгляд) серьезная проблема согласованности.

Для получения подробной информации о том, что в настоящее время реализовано, я предлагаю начать с чтения RFC. Но в этом документе еще немало того, что не было реализовано, и реализовано то, чего в этом документе не было. Следующие два сообщения могут быть полезны, чтобы лучше понять их:

В чем подвох?

Некоторые из функций, которые я перечислил выше, заставят самых опытных разработчиков съежиться при одном упоминании (а именно, eval и goto). Другие используются так часто, что у некоторых может возникнуть вопрос, почему я включил их в список. В большинстве случаев они используются для решения проблем, которые им не следует пытаться решать (например, попытка парсить HTML с помощью регулярных выражений). Они могут привести к негативным последствиям в коде (таким как уязвимости безопасности или тесная связь). Они могут значительно затруднить чтение (попробуйте прочитать это регулярное выражение). Некоторые из них настолько плохи, что их использование рассматривается как не более чем запах кода…

Не поймите меня неправильно, каждая из тех функций, которые я перечислил в первом абзаце, весьма полезна для решения определенных проблем. На самом деле они могут быть единственным способом решения некоторых проблем. Разница между этими функциями и другими функциями, которая заставляет меня классифицировать их как «часто злоупотребляемые», заключается в том, что значительная часть их использования может рассматриваться как «плохая».

Мои опасения по поводу трейтов

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

  • Тесная связь

Поскольку трейты разрешаются во время компиляции, их использование ничем не отличается от расширений в том смысле, что оно тесно связывает реализацию трейтов с используемым классом. На самом деле это может снизить возможность повторного использования и полезность самого класса. Это проблемы, для решения которых мы обычно используем шаблоны проектирования (такие как Decorator, Composite и Bridge).

  • Тестируемость

Черты модульного тестирования будут интересной задачей. Конечно, мы можем создать макет или заглушку, использующую трейт, и протестировать его, но с точки зрения взаимодействия между классом и трейтом довольно значительны. Должны ли мы тогда просто тестировать классы реализации трейта и предположить, что если они будут протестированы хорошо, то трейт будет таким же (аналогично защищенным и закрытым методам)? Я признаю, что в долгосрочной перспективе это может не иметь существенного значения (поскольку я уверен, что сообщество примет хорошую методологию)…

  • Принцип единой ответственности

Определенно есть случаи, когда трейты могут использоваться для реализации общей функциональности там, где наследование невозможно (например, пример отражения в RFC). Однако также существует возможность (и искушение) реализовать все виды кода в классе, потому что это упрощает пересечение линии SRP и создание обманчивых богов-классов. Я называю их вводящими в заблуждение, потому что их объявление выглядит так, как будто оно соответствует SRP, но доступный объект среды выполнения действительно делает много вещей.

  • Понятность

Прямо сейчас, чтобы понять, что делает класс (и как он это делает), вам нужно пройти вверх по цепочке наследования, чтобы определить, как класс работает. Сохраняя глубину наследования на достаточно небольшом уровне (обычно я выбираю 3 в качестве мягкого предупреждения и 6 в качестве ошибки), это упрощает понимание класса. Но теперь мы расширяем этот поиск. Каждый класс в цепочке может иметь произвольное количество свойств, связанных с ним. Таким образом, даже если цепочка наследования имеет глубину всего 3, может быть 50 мест, где код определен для сборки этого класса. Так что теперь вместо цепочки наследования действительно есть дерево наследования, которое может значительно усложнить понимание кодовой базы. А когда вы принимаете во внимание методы алиасинга, это становится еще более интересной задачей.

Заключение

С учетом сказанного, я определенно не сторонник добавления трейтов. Они являются очень полезной конструкцией, и их способность помочь приложению в архитектуре значительна. Я просто задаюсь вопросом, будут ли сегодня они рассматриваться как eval и goto, опасные инструменты, которые приносят больше вреда, чем пользы, использование которых является не чем иным, как запахом кода…

Что вы думаете? Справедливы ли мои опасения? Или я слишком осторожен? Разделяете ли вы некоторые из тех же опасений? Есть ли у вас дополнительные опасения?


Источники:

  1. Вопрос: https://youtu.be/9aGv-ylsYDI?t=2168

  2. Ответ (текст выше): https://chulakov.ru/notes/development/trejty-v-php-zlo-nas-vzglad-na-problemu

  3. Что не так с трейтами? https://habr.com/ru/companies/skyeng/articles/534152/

  4. Are Traits The New Eval? https://blog.ircmaxell.com/2011/07/are-traits-new-eval.html

Tags

Нет комментариев

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Рубрики


Подпишись на новости
👋

Есть вопросы?