-
-
Notifications
You must be signed in to change notification settings - Fork 1
Feature Configuration
Регистрация сервисов не только кодом, но и декларативными файлами: PHP, JSON, YAML, XML — с загрузкой из каталога и приоритетами. Подробный туториал — Конфигурация, справочник формата — Configuration-reference.
ContainerConfigurator читает конфиг через набор лоадеров (PhpConfigurationLoader, JsonConfigurationLoader, YamlConfigurationLoader, XmlConfigurationLoader), нормализует его в определения и применяет к контейнеру. Можно загрузить один файл или каталог — тогда файлы сливаются с учётом приоритета (например, окружение переопределяет базовые настройки).
// services.yaml
services:
App\Db:
factory: 'App\DbFactory'
App\LoggerInterface:
alias: App\FileLogger
// bootstrap:
$configurator->loadFile(__DIR__ . '/config/services.yaml');
$configurator->loadDirectory(__DIR__ . '/config'); // слияние с приоритетамиYAML требует ext-yaml (опционально; для JSON/PHP/XML не нужен).
Секция parameters + подстановки в значениях (как в Symfony) — разрешаются до применения к контейнеру:
parameters:
db_host: '%env(DB_HOST:localhost)%' # env с дефолтом
db_port: '%env(int:DB_PORT:5432)%' # типизированный env (int/bool/float/json)
services:
app.dsn: 'pgsql://%db_host%:%db_port%/app' # интерполяция параметров-
%имя%— параметр (целиком → «сырое» значение любого типа; внутри строки → интерполяция); -
%env(VAR)%/%env(VAR:default)%— переменная окружения (бросает исключение, если не задана и нет дефолта); -
%env(int:VAR)%/bool/float/json/string— типизированное значение; -
%%— экранированный процент. Параметры разных слоёв конфига мёржатся (поздний переопределяет).
Ключ calls вызывает методы сервиса после конструирования — декларативный аналог Symfony calls:. Каждая запись — имя метода либо [метод, [аргументы]]; применяется к каждому новому экземпляру.
// PHP / YAML / JSON
'services' => [
'app.report' => [
'class' => App\Report::class,
'calls' => [
['setPrefix', ['app_']], // литерал (можно %параметр% / %env(...)%)
['setLogger', ['@logger']], // '@id' — ссылка на другой сервис
['enable'], // метод без аргументов
],
],
],- Аргумент
@id— ссылка на сервис ($c->get('id'));@@в начале строки — экранированный литерал@. - Строковые ключи в списке аргументов передаются как именованные параметры метода.
- Некорректная запись (без имени метода) — ошибка на этапе применения конфига; несуществующий метод — при резолве. Поддержано в PHP/YAML/JSON.
Ключ factory создаёт сервис вызовом метода — экземпляра другого сервиса или статического метода класса (аналог Symfony factory:):
'services' => [
// фабрика-экземпляр: вызвать метод сервиса '@app.factory'
'app.report' => [
'factory' => ['@app.factory', 'createReport'],
'arguments' => ['%report.type%', '@app.clock'],
],
// статическая фабрика: Class::method(...)
'app.uuid' => ['factory' => [Ramsey\Uuid\Uuid::class, 'uuid4']],
// строковая форма статической фабрики
'app.now' => ['factory' => 'App\Clock::now'],
],-
['@id', 'method']— метод сервиса-экземпляра;['Class', 'method']или'Class::method'— статический метод. -
argumentsразрешаются как уcalls: литералы,%параметры%/%env%, ссылки@id, именованные ключи. - Некорректный
factory— ошибка при применении конфига; несуществующий метод — при резолве.
Общую часть определений можно вынести в шаблон и переиспользовать (аналог Symfony parent:/abstract:):
'services' => [
// шаблон: сам сервисом не регистрируется
'_repository' => [
'abstract' => true,
'class' => App\BaseRepository::class,
'calls' => [['setConnection', ['@db']]],
],
'user.repository' => [
'parent' => '_repository', // наследует class + calls
'calls' => [['setTable', ['users']]], // добавляется к calls родителя
],
],-
parent: 'id'— потомок получает ключи родителя; одноимённые скалярные ключи (class,factory,lazy) потомок переопределяет, списокcallsдополняется (сначала родительские, затем потомка). -
abstract: true— определение-шаблон, самим сервисом не регистрируется (has()→false). - Неизвестный
parent— ошибка при применении конфига. Рекомендуется помечать шаблоныabstract, чтобы ихcallsне применялись к другим сервисам того же класса.
Ключ deprecated помечает сервис устаревшим: при создании нового экземпляра эмитится E_USER_DEPRECATED (аналог Symfony deprecated:):
'services' => [
'legacy.mailer' => [
'class' => App\LegacyMailer::class,
'deprecated' => 'Используйте App\Mailer вместо legacy.mailer.',
],
'old.repo' => ['class' => App\OldRepo::class, 'deprecated' => true], // сообщение по умолчанию
],-
deprecated: 'сообщение'— своё сообщение;deprecated: true— сообщение по умолчанию;false/отсутствие — без пометки. - Предупреждение эмитится через хук before-resolving перед созданием нового экземпляра (для singleton — при первом обращении).
Секция when задаёт переопределения по имени окружения; активное окружение — в ключе environment (обычно %env(APP_ENV)%). Совпавшие переопределения сливаются поверх базовой конфигурации (аналог Symfony when@env):
'environment' => '%env(APP_ENV:prod)%',
'services' => [
'mailer' => ['class' => App\SmtpMailer::class], // база (prod)
],
'when' => [
'dev' => ['services' => ['mailer' => ['class' => App\NullMailer::class]]],
'test' => ['services' => ['mailer' => ['class' => App\ArrayMailer::class]]],
],- Переопределения мёржатся по секциям: сервисы/alias'ы с тем же id заменяются, новые — добавляются; несуществующие в базе секции добавляются целиком.
- Если
environmentне задан или нет веткиwhen.<environment>— применяется только база.
Перед применением конфигурация проверяется (fail-fast): неизвестная секция верхнего уровня (например, опечатка servcies вместо services) сразу бросает ContainerException с перечнем допустимых секций — типичный «молчаливый» баг не проходит незаметно.
По умолчанию типы значений известных секций обрабатываются мягко (устойчивое слияние слоёв). Чтобы включить строгую проверку типов, добавьте ключ strict: true в конфигурацию — тогда неверный тип любой секции тоже отклоняется fail-fast: services / parameters / aliases / bind / tags / autowire / scan / contextual / register_attributes / autowiring / when обязаны быть массивами, environment — строкой, priority — целым.
# services.yaml
strict: true # включить строгую проверку типов секций
services:
App\Db: { factory: 'App\DbFactory' }
# services: 'oops' → ContainerException: секция "services" должна быть типа "array"Строгий режим — opt-in: без ключа strict поведение полностью совместимо с прежним.
- Единый обзор графа в файлах — удобно для больших приложений и не-программистов.
- Разделение окружений через каталог + приоритеты (base → prod/test override).
- Четыре формата на выбор — под привычки команды (в отличие от контейнеров с одним форматом).
- Декларативный конфиг многословнее autowiring для простых классов.
- YAML/XML — дополнительный слой парсинга (стоимость на старте; в проде — compiled).
- Хранить в конфиге то, что меняется по окружению (DSN, ключи, реализации), остальное отдавать autowiring.
- Разбивать на каталог:
config/services/*.yaml+ окружение поверх. - Не класть секреты в конфиг — только ссылки на защищённое хранилище/ENV.
- Описывать в конфиге весь тривиальный граф, дублируя то, что решает autowiring.
- Смешивать бизнес-данные и определения сервисов в одном файле.
| Контейнер | Аналог |
|---|---|
| PHP-DI | PHP-массивы; JSON/YAML — ограниченно ( |
| Symfony | YAML / XML / PHP — эталонная система конфигов |
| Laravel | PHP service providers; декларативных файлов сервисов нет ( |
| Pimple | нет (❌ — только код) |
| Nette | NEON (свой формат) |
CloudCastle, Symfony, Nette — богатая декларативная конфигурация; CloudCastle покрывает PHP/JSON/YAML/XML.
См. также: Конфигурация (гайд) · Справочник конфигурации · Сканирование каталога.
CloudCastle DI · · PHP 8.1+ · PSR-11
GitHub · Packagist · Releases · Discussions · Сравнение
Исходники Wiki — каталог wiki/ в репозитории (синхронизация через GitHub Actions)
- 🏗️ Архитектура
- ⚡ Быстрый старт
- 📊 Сравнение — 5 аналогов, таблица + победители
- 🧩 Возможности (детально) — каждая фича: принцип, +/−, аналоги
- 🧪 Bootstrap
- 🚀 Compiled container
- 🔗 Contextual binding
- 🤖 Autowiring
- 📄 Конфигурация
- 📖 Справочник конфигурации
- 📂 Сканирование классов
- 🌍 Глобальный реестр
- 🏷️ Теги и декораторы
- 🔗 call(), bind(), hooks
- 🔄 Прототипы, alias, lazy, lazyGhost
- 📋 Справочник API
- 🏭 Фабрики и singleton