Прекратите использовать «расширения» в PHP
Используете ли вы
абстрактные классы или расширяющие классы в коде вашего домена? Надеюсь, вы, , с этого дня остановите . Опубликовано в·
Чтение: 4 мин.·
12 августа 2022 г. 08 в тему. Сегодня мы поговорим о коде, который не относится ни к какому фреймворку. Расширение классов может быть необходимо, потому что выбранный вами фреймворк (Laravel, Symfony, как вы его назовете) или библиотека, которую вы используете, могут вынудить вас сделать это.Сегодня я хочу обсудить код ядра вашего приложения. Называть его можно как угодно: корневой код, основной домен , код DDD . Код, за который вы и/или ваша команда отвечаете.
Используете ли вы в своем коде такие ключевые слова, как « расширяет » или « абстракция »? Я профессионально программирую с 2015 года, и с тех пор я не нашел причин использовать абстрактные классы или расширять какой-либо класс в своем коде. Я до сих пор помню фантастическую статью Марко Пиветты, которая навсегда изменила то, как я разрабатываю свой код.
В статье рассказывается, почему классы final отлично подходят для вашего кода. Вот как с тех пор выглядит мой шаблон класса в PHPStorm для каждого проекта:
Я уже видел и слышал это слишком много раз. Дает ли расширение классов гибкость? Насколько гибко вам дано такое наследование классов:
Любое изменение в корневых классах, как здесь BaseUser , может иметь катастрофические последствия для всего приложения. Я вижу здесь только возможные проблемы, но никакой выгоды. Что вам нужно сделать, это:
Использовать интерфейсы; предотвратить наследование, применив ключевое слово final
Вместо этого код должен выглядеть так:
Многие люди потом говорят мне: черты?» Но тогда эта черта будет хрупкой частью. А вот и второй совет:
Перестаньте бояться повторяющегося кода
Так работает наш мозг: он заставляет вас искать закономерности. Отказ от абстрактных классов и наследования помогает предотвратить неудачные кодовые решения.
Вам нужны новые функции? Начните с интерфейса. Используйте doc-блоки для описания ввода, вывода и причины этого. Это может показаться замедлением, но это помогает вам спланировать то, что вам действительно нужно.
Я хотел бы поделиться примером того, насколько мощной является эта техника. Давайте представим, что нам нужно отправлять уведомления в нашем приложении. Неважно, как и кому. Мы заботимся только о функциональности.
Начнем с определения уведомления, которое будет отправлено. Мы действительно не заботимся о каких-либо деталях. Это всего лишь отправная точка для типов уведомлений (смс-сообщение, сообщение электронной почты, сообщение WhatsApp и т. д.):
Теперь давайте создадим менеджера, который будет выполнять всю работу. Тем не менее, он не заботится о каких-либо деталях сообщения. Это гарантирует увидеть выполненную работу.
Вот что я называю истинной гибкостью. Какие уведомления могут вам понадобиться?
Уведомление по электронной почте
Уведомление WhatsApp
Этот список можно продолжать бесконечно. Используя функцию внедрения зависимостей вашего фреймворка, можно поменять реализацию интерфейса так, чтобы приложение даже не заметило этого. Таким образом, ваше приложение отделено от деталей системы уведомлений. Придумаем простую реализацию. Нам понадобится транспортный механизм для доставки наших уведомлений. Мы могли бы использовать еще один интерфейс:
и настоящий транспорт, который доставляет сообщения электронной почты:
, наконец, простой менеджер уведомлений:
Я уже люблю каждый бит этого кода:
- принцип единой ответственности: каждая часть заботится только о своей части
- соблюдается принцип открытости-закрытости: мы можем изменять функциональность как угодно, не нарушая текущую функциональность (добавлять новые транспорты, добавлять новые типы уведомлений и т. д.)
- изменение транспортных механизмов не влияет на другие части приложения
- изменение любой части модуля уведомлений не влияет на приложение, пока вы придерживаетесь контракта интерфейса, который мы разработали в начале
Поскольку у нас есть вся функциональность, все, что нам нужно сделать, это создать уведомление. Допустим, мы хотим отправлять приветственное письмо каждый раз, когда пользователь регистрируется. Нам нужна реализация интерфейса уведомления по электронной почте:
Служба, которая создаст уведомление из пользовательского объекта:
Я подключусь к событию пост-регистрации моего приложения, чтобы отправить уведомление. И вуаля!
Услуги по декорированию гибких расширений
Последний мощный метод, которым я хотел бы поделиться, — это шаблон Decorator. Я нахожу это очень полезным, так как позволяет безопасно расширять функциональность класса, не погружаясь в его внутренности.
Допустим, у нашего SMTP-сервера время от времени возникают проблемы, и он любит препятствовать доставке электронной почты. Благодаря шаблону декоратора мы можем ввести повторную отправку на любой транспорт:
Есть сомнения? Мысли? Пожалуйста, оставьте мне комментарий о том, что вы думаете. Давайте вместе сделаем наш код красивым.
Эта история имела для вас какое-то значение ? Пожалуйста, поддержите мою работу, оставив 👏 хлопок в знак признательности n. Знаете ли вы, что можно хлопать более одного раза? 🥰 Спасибо.
extends — Документация — Twig
Вы читаете документацию по Twig 2.x. Перейти к документации для Twig 1.х. 3.х.
Тег extends
может использоваться для расширения шаблона из другого.
Примечание
Как и PHP, Twig не поддерживает множественное наследование. Таким образом, вы можете иметь только один тег расширения, вызываемый для каждого рендеринга. Однако Twig поддерживает горизонтальные повторное использование.
Давайте определим базовый шаблон, base.html
, который определяет простой HTML-код.
скелетный документ:
В этом примере теги блоков определяют четыре блока, которые являются дочерними. шаблоны могут быть заполнены.
Все, что делает тег block
, это сообщает обработчику шаблонов, что дочерний элемент
шаблон может переопределить эти части шаблона.
Дочерний шаблон может выглядеть так:
Ключевым здесь является тег extends
. Он сообщает механизму шаблонов, что это
шаблон «расширяет» другой шаблон. Когда система шаблонов оценивает это
шаблон, сначала он находит родителя. Тег extends должен быть первым тегом
в шаблоне.
Обратите внимание, что, поскольку дочерний шаблон не определяет блок нижнего колонтитула ,
вместо этого используется значение из родительского шаблона.
Нельзя определить несколько блок
тегов с одинаковыми именами в одном
шаблон. Это ограничение существует, потому что блочный тег работает в обоих случаях.
направления. То есть блочный тег не просто заполняет дыру, но и
определяет содержимое, которое заполняет дыру в родительском элементе . Если бы было два блокируют
Если вы хотите распечатать блок несколько раз, вы можете использовать блок
функция:
Можно отображать содержимое родительского блока с помощью родительская функция. Это возвращает результаты родительский блок:
Twig позволяет ставить имя блока после закрывающего тега для лучшего
удобочитаемость (имя после слова endblock
должно совпадать с именем блока):
Блоки могут быть вложены друг в друга для более сложных макетов. По умолчанию блоки имеют доступ к переменным из внешних областей видимости:
Для блоков с небольшим содержанием можно использовать сокращенный синтаксис. следующие конструкции делают то же самое:
Twig поддерживает динамическое наследование, используя переменную в качестве базового шаблона:
Если переменная оценивается как \Twig\Template
или \Twig\TemplateWrapper
Например, Twig будет использовать его в качестве родительского шаблона:
Вы также можете предоставить список шаблонов, существование которых проверяется. первый существующий шаблон будет использоваться как родительский:
Поскольку имя родительского шаблона может быть любым допустимым выражением Twig, можно сделать механизм наследования условным:
В этом примере шаблон будет расширять шаблон макета "minimum.html"
если автономная переменная
оценивается как true
и "base.html"
в противном случае.
Блок позволяет изменить способ отображения определенной части шаблона. но это никоим образом не мешает логике вокруг него.
Давайте рассмотрим следующий пример, чтобы проиллюстрировать, как работает блок и многое другое. главное, как это не работает:
Если рендерить этот шаблон, то результат будет точно таким же с или
без тега блока
. Блок
внутри цикла for
— это просто способ
чтобы сделать его переопределяемым дочерним шаблоном:
Теперь при рендеринге дочернего шаблона цикл будет использовать блок определенный в дочернем шаблоне вместо определенного в базовом; в выполненный шаблон эквивалентен следующему:
Возьмем другой пример: блок, включенный в оператор if
:
Вопреки тому, что вы могли бы подумать, этот шаблон не определяет блок
условно; он просто делает переопределяемым дочерним шаблоном вывод
что будет отображаться, когда условие
.