Конфигурация
Всё, что нужно для настройки контейнера Wirebox.
Содержание
ContainerBuilder
ContainerBuilder — главная точка входа для настройки контейнера:
use AsceticSoft\Wirebox\ContainerBuilder;
$builder = new ContainerBuilder(projectDir: __DIR__);
Параметр projectDir используется как базовый путь для поиска файлов .env.
Сканирование директорий
Сканируйте одну или несколько директорий для автоматической регистрации всех конкретных классов. Абстрактные классы, интерфейсы, трейты и перечисления (enum) автоматически пропускаются:
$builder->scan(__DIR__ . '/src');
$builder->scan(__DIR__ . '/modules');
Сканер использует токенизатор PHP для быстрого и надёжного обнаружения классов без загрузки файлов.
Исключение файлов
Исключайте файлы по glob-паттерну. Паттерны задаются относительно сканируемой директории:
$builder->exclude('Entity/*');
$builder->exclude('*Test.php');
$builder->scan(__DIR__ . '/src');
Вызывайте exclude() до scan() — паттерны исключения применяются к последующим сканированиям.
Можно также исключить отдельные классы атрибутом #[Exclude]:
use AsceticSoft\Wirebox\Attribute\Exclude;
#[Exclude]
class InternalHelper
{
// Не будет зарегистрирован в контейнере
}
Автопривязка интерфейсов
При сканировании, если у интерфейса ровно одна реализация в отсканированных директориях, Wirebox автоматически привязывает интерфейс к этой реализации.
Если найдено две или более реализации, привязка становится неоднозначной, и build() выбросит ContainerException. Разрешите неоднозначность явной привязкой через bind():
$builder->scan(__DIR__ . '/Services');
// У PaymentInterface есть StripePayment и PayPalPayment — неоднозначность!
$builder->bind(PaymentInterface::class, StripePayment::class);
Интерфейсы с атрибутом #[AutoconfigureTag] исключаются из проверки на неоднозначность, так как множественные реализации для них ожидаемы. См. Автоконфигурация.
Привязка интерфейсов
Явно привяжите интерфейс (или абстрактный класс) к конкретной реализации:
$builder->bind(LoggerInterface::class, FileLogger::class);
$builder->bind(CacheInterface::class, RedisCache::class);
При разрешении зависимости по type hint контейнер сначала проверяет привязки, а затем пытается создать конкретный класс напрямую.
Регистрация через фабрику
Зарегистрируйте сервис с фабричным замыканием для сложной логики создания:
use AsceticSoft\Wirebox\Container;
$builder->register(PDO::class, function (Container $c) {
return new PDO(
sprintf('mysql:host=%s;port=%d;dbname=app',
$c->getParameter('db.host'),
$c->getParameter('db.port'),
),
);
});
Замыкание получает экземпляр Container, из которого можно получить другие сервисы и параметры.
Фабричные замыкания не поддерживаются в компилируемом контейнере — они требуют runtime-выполнения. Где возможно, используйте автовайринг с атрибутами #[Param] или #[Inject].
Fluent Definition API
register() возвращает объект Definition с fluent-интерфейсом для тонкой настройки:
$builder->register(FileLogger::class)
->transient() // Новый экземпляр каждый раз
->lazy() // Отложенное создание
->tag('logger') // Добавить тег
->call('setFormatter', [JsonFormatter::class]); // Setter-инъекция
Доступные методы
| Метод | Описание |
|---|---|
singleton() |
Один экземпляр на контейнер (по умолчанию) |
transient() |
Новый экземпляр при каждом вызове get() |
lazy() |
Возвращает прокси; реальный экземпляр создаётся при первом обращении |
eager() |
Всегда создаётся немедленно (отключает lazy по умолчанию) |
tag(string ...$tags) |
Добавить один или несколько тегов для групповой выборки |
call(string $method, array $args) |
Настройка setter-инъекции (вызов после конструктора) |
Setter-инъекция
Настройте вызов методов после создания сервиса:
$builder->register(Mailer::class)
->call('setTransport', [SmtpTransport::class])
->call('setLogger', [FileLogger::class]);
Аргументы могут быть:
- Имена классов — разрешаются из контейнера
- Скалярные значения — передаются как есть
Параметры
Определяйте параметры, ссылающиеся на переменные окружения:
$builder->parameter('db.host', '%env(DB_HOST)%');
$builder->parameter('db.port', '%env(int:DB_PORT)%');
$builder->parameter('app.debug', '%env(bool:APP_DEBUG)%');
$builder->parameter('rate.limit', '%env(float:RATE_LIMIT)%');
Приведение типов
Поддерживаемые приведения внутри выражений %env(...)%:
| Тип | Пример | Результат |
|---|---|---|
string (по умолчанию) |
%env(DB_HOST)% |
"localhost" |
int |
%env(int:DB_PORT)% |
5432 |
float |
%env(float:RATE_LIMIT)% |
1.5 |
bool |
%env(bool:APP_DEBUG)% |
true |
Встроенные выражения
Выражения с переменными окружения можно встраивать в строки:
$builder->parameter('dsn', 'mysql:host=%env(DB_HOST)%;port=%env(DB_PORT)%');
// Результат: "mysql:host=localhost;port=5432"
Простые значения
Параметры могут быть обычными значениями без env-выражений:
$builder->parameter('pagination.limit', 25);
$builder->parameter('app.name', 'My Application');
Режим lazy по умолчанию
По умолчанию ContainerBuilder включает lazy-режим — все сервисы создаются как ленивые прокси, если у них нет явного атрибута #[Eager]. Обычно это то, что нужно для производительности.
Чтобы отключить lazy по умолчанию:
$builder->defaultLazy(false);
При отключении сервисы создаются немедленно, если явно не помечены #[Lazy].
Подробнее: Ленивые прокси.
Сборка контейнера
После настройки вызовите build() для создания контейнера:
$container = $builder->build();
Метод build():
- Применяет lazy-режим по умолчанию к определениям без явных настроек
- Обнаруживает небезопасные циклические зависимости
- Создаёт и возвращает экземпляр
Container
build() валидирует конфигурацию и выбрасывает исключения при неоднозначных привязках или небезопасных циклических зависимостях. Исправьте их перед деплоем.
Далее
- Атрибуты — декларативная настройка PHP-атрибутами
- Переменные окружения — dotenv и уровни приоритета
- Компилируемый контейнер — оптимизация для продакшена
- Продвинутые возможности — автоконфигурация, теги, ленивые прокси