Skip to content

Feature Extensions

github-actions[bot] edited this page Jul 8, 2026 · 1 revision

🧩 Расширения и compiler passes

← Возможности · Главная · Сравнение

Механизм подключения сторонних пакетов (расширения) и сквозной обработки графа (compiler passes) — аналог bundle-extensions + compiler passes Symfony и DI-extensions Nette.

Принцип работы

  • Расширение реализует ContainerExtensionInterface::load($container) — регистрирует сервисы пакета. Подключается через registerExtension($ext), который сразу вызывает load().
  • Compiler pass реализует CompilerPassInterface::process($container) — модифицирует граф после регистрации всех сервисов. Копится через addCompilerPass($pass) и выполняется в build().

Порядок: подключаете расширения → добавляете проходы → build() прогоняет проходы → (опционально) freeze().

$c = new Container();
$c->registerExtension(new CachePackageExtension());     // пакет регистрирует свои сервисы
$c->registerExtension(new QueuePackageExtension());

$c->addCompilerPass(new class implements CompilerPassInterface {
    public function process(ContainerInterface $c): void {
        // собрать все реализации по тегу и связать с потребителем
        $c->set('listeners.ids', $c->getTaggedIds('event.listener'));
    }
});

$c->build();     // прогон проходов после регистрации всего графа
$c->freeze();    // зафиксировать

Плюсы

  • Экосистема пакетов: сторонний код подключается одной строкой (registerExtension), не зная деталей приложения.
  • Сквозная сборка: compiler pass видит весь граф — идеально для «собрать по тегу и связать», валидации, подмены определений.
  • Явный build() — предсказуемая точка сборки перед freeze().

Минусы

  • Расширения выполняются сразу при registerExtension (нет отдельной фазы «сначала все load, потом все process», кроме build() для проходов).
  • На compiled-контейнере недоступно — расширения/проходы применяются до компиляции на runtime-контейнере.

✅ Рекомендуется

  • Пакеты — через ContainerExtensionInterface; кросс-модульную проводку (tagged → потребитель) — через compiler pass.
  • Вызывать build() один раз в конце bootstrap, затем freeze().

❌ Антипаттерны

  • Тяжёлая логика/IO в load() или process() — это фаза сборки графа, а не работы приложения.
  • Взаимозависимый порядок расширений, где пакет A требует, чтобы B загрузился раньше, — делайте связывание в compiler pass, а не в порядке registerExtension.

Аналоги в других контейнерах

Контейнер Аналог
PHP-DI нет механизма расширений/проходов (❌)
Symfony bundle extensions + compiler passes (эталон)
Laravel service providers (⚠️ — есть расширения, нет compiler-pass фазы)
Pimple ServiceProviderInterface (⚠️ — только register)
Nette DI extensions (loadConfiguration / beforeCompile)

CloudCastle, Symfony, Nette — расширения + сквозные проходы.

См. также: Теги и tagged services · Autoconfigure.

Clone this wiki locally