1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>На протяжении всего курса, мы говорили про процесс инициализации, внутри которого создаются необходимые объекты. Затем эти объекты используются в прикладном коде. К таким объектам относятся: соединение с базой данных, логгер, кеш, шаблонизатор, интеграция с внешними сервисами и многое другое.</p>
1
<p>На протяжении всего курса, мы говорили про процесс инициализации, внутри которого создаются необходимые объекты. Затем эти объекты используются в прикладном коде. К таким объектам относятся: соединение с базой данных, логгер, кеш, шаблонизатор, интеграция с внешними сервисами и многое другое.</p>
2
<p>В простых ситуациях, там где объектов немного и мы сами управляем кодом (а не используем фреймворки, определяющие структуру), зависимости можно внедрять "руками":</p>
2
<p>В простых ситуациях, там где объектов немного и мы сами управляем кодом (а не используем фреймворки, определяющие структуру), зависимости можно внедрять "руками":</p>
3
<p>В коде, который активно использует инверсию зависимостей, инициализация кода выглядит как матрёшка из объектов. Объекты верхнего уровня принимают на вход объекты с нижних слоёв, шаг за шагом собирая готовое приложение.</p>
3
<p>В коде, который активно использует инверсию зависимостей, инициализация кода выглядит как матрёшка из объектов. Объекты верхнего уровня принимают на вход объекты с нижних слоёв, шаг за шагом собирая готовое приложение.</p>
4
<p>С ростом числа объектов, процесс сборки усложняется и становится утомительным. Появляются ситуации, в которых объекты нужны в самой глубине кода, но прокинуть их можно только пройдя множество уровней. В популярных фреймворках инициализация может включать в себя создание и внедрение сотен объектов. Страшно даже представить, что придётся писать этот код вручную.</p>
4
<p>С ростом числа объектов, процесс сборки усложняется и становится утомительным. Появляются ситуации, в которых объекты нужны в самой глубине кода, но прокинуть их можно только пройдя множество уровней. В популярных фреймворках инициализация может включать в себя создание и внедрение сотен объектов. Страшно даже представить, что придётся писать этот код вручную.</p>
5
<p>Для решения данной задачи, используется два подхода (шаблона проектирования). Ниже поговорим про каждый из них</p>
5
<p>Для решения данной задачи, используется два подхода (шаблона проектирования). Ниже поговорим про каждый из них</p>
6
<h2>Локатор (Service Locator)</h2>
6
<h2>Локатор (Service Locator)</h2>
7
<p>Самый простой способ внедрять зависимости в таких системах - сервис локатор. Это объект, который содержит внутри себя все зависимости. Любой объект, которому нужен какой-либо сервис, обращается за ним к сервис локатору.</p>
7
<p>Самый простой способ внедрять зависимости в таких системах - сервис локатор. Это объект, который содержит внутри себя все зависимости. Любой объект, которому нужен какой-либо сервис, обращается за ним к сервис локатору.</p>
8
<p>Возьмём для примера микрофреймворк Slim. У него есть расширение PHP-View, которое добавляет шаблонизатор в фреймворк. Попробуем внедрить это расширение через Service Locator:</p>
8
<p>Возьмём для примера микрофреймворк Slim. У него есть расширение PHP-View, которое добавляет шаблонизатор в фреймворк. Попробуем внедрить это расширение через Service Locator:</p>
9
-
<p>Вот такой нехитрый подход для внедрения зависимостей. По нему написаны сотни статей со всевозможными вариа��иями его создания и использования. В большинстве из них локатор рассматривается как антипаттерн. Так как прикладной код знает про его существование.</p>
9
+
<p>Вот такой нехитрый подход для внедрения зависимостей. По нему написаны сотни статей со всевозможными вариациями его создания и использования. В большинстве из них локатор рассматривается как антипаттерн. Так как прикладной код знает про его существование.</p>
10
<h2>Контейнер (DI Container)</h2>
10
<h2>Контейнер (DI Container)</h2>
11
<p>Вершиной эволюции инверсии зависимостей считается DI Container. Продвинутые контейнеры, это целые фреймворки, которые занимаются инициализацией приложения, собирают необходимые объекты и прокидывают их друг в друга. В некоторых экосистемах, контейнер - центральная часть всей системы, которая занимается её оркестрацией (управлением). В Java, например, это Spring Framework. Он с лёгкостью может собирать и веб-приложение и демонов.</p>
11
<p>Вершиной эволюции инверсии зависимостей считается DI Container. Продвинутые контейнеры, это целые фреймворки, которые занимаются инициализацией приложения, собирают необходимые объекты и прокидывают их друг в друга. В некоторых экосистемах, контейнер - центральная часть всей системы, которая занимается её оркестрацией (управлением). В Java, например, это Spring Framework. Он с лёгкостью может собирать и веб-приложение и демонов.</p>
12
<p>Ключевое отличие контейнера от локатора в том, что зависимости из контейнера попадают внутрь приложения прозрачно. Прикладной код не догадывается о существовании контейнера, он лишь видит объекты, которых ждёт. Для инъекции этих зависимостей используются стандартные подходы: либо через конструктор, либо через сеттеры и аргументы методов.</p>
12
<p>Ключевое отличие контейнера от локатора в том, что зависимости из контейнера попадают внутрь приложения прозрачно. Прикладной код не догадывается о существовании контейнера, он лишь видит объекты, которых ждёт. Для инъекции этих зависимостей используются стандартные подходы: либо через конструктор, либо через сеттеры и аргументы методов.</p>
13
<p>Снова посмотрим на Slim и интеграцию с PHP-View, но уже через встроенный контейнер. Обработчик запроса получает renderer через метод get(). Он не знает ничего про контейнер и про то, как зависимость попала внутрь $this.</p>
13
<p>Снова посмотрим на Slim и интеграцию с PHP-View, но уже через встроенный контейнер. Обработчик запроса получает renderer через метод get(). Он не знает ничего про контейнер и про то, как зависимость попала внутрь $this.</p>
14
<p>Помимо отсутствия глобального объекта в виде локатора, мы получаем еще ряд преимуществ, которые начинают играть роль с ростом приложения. Так как контейнер это объект, встроенный в процесс работы фреймворка, то он может связывать свою работу с его логикой:</p>
14
<p>Помимо отсутствия глобального объекта в виде локатора, мы получаем еще ряд преимуществ, которые начинают играть роль с ростом приложения. Так как контейнер это объект, встроенный в процесс работы фреймворка, то он может связывать свою работу с его логикой:</p>
15
<ul><li>Поддерживать работу с синглтонами и пулом объектов. Можно управлять состоянием объектов, создавая их один раз и переиспользуя в течение жизни приложения или отдельного запроса.</li>
15
<ul><li>Поддерживать работу с синглтонами и пулом объектов. Можно управлять состоянием объектов, создавая их один раз и переиспользуя в течение жизни приложения или отдельного запроса.</li>
16
<li>Интегрироваться с middleware и событиями. Во многих фреймворках контейнер связывается с системой middleware или событийной моделью, упрощая внедрение зависимостей в обработчики событий и промежуточные слои.</li>
16
<li>Интегрироваться с middleware и событиями. Во многих фреймворках контейнер связывается с системой middleware или событийной моделью, упрощая внедрение зависимостей в обработчики событий и промежуточные слои.</li>
17
<li>Обеспечивать автоматическую резолвинг-зависимостей. В продвинутых контейнерах можно регистрировать классы без явного указания всех зависимостей - контейнер сам анализирует конструкторы и подставляет нужные объекты.</li>
17
<li>Обеспечивать автоматическую резолвинг-зависимостей. В продвинутых контейнерах можно регистрировать классы без явного указания всех зависимостей - контейнер сам анализирует конструкторы и подставляет нужные объекты.</li>
18
</ul><p>В PHP контейнеры имеют настолько важную роль, что их интерфейс был унифицирован через<a>PSR-11</a>.</p>
18
</ul><p>В PHP контейнеры имеют настолько важную роль, что их интерфейс был унифицирован через<a>PSR-11</a>.</p>