Быстрый старт
Начните работу с Wirebox за 5 минут.
Содержание
Установка
Установите Wirebox через Composer:
composer require ascetic-soft/wirebox
Требования:
- PHP >= 8.4
- psr/container ^2.0
Ваш первый контейнер
Шаг 1: Создайте сервисы
// src/Mailer.php
namespace App;
class Mailer
{
public function send(string $to, string $message): void
{
// отправка письма...
}
}
// src/UserService.php
namespace App;
class UserService
{
public function __construct(
private Mailer $mailer,
) {
}
public function register(string $email): void
{
// создание пользователя...
$this->mailer->send($email, 'Добро пожаловать!');
}
}
Шаг 2: Соберите контейнер
// bootstrap.php
use AsceticSoft\Wirebox\ContainerBuilder;
require_once __DIR__ . '/vendor/autoload.php';
$builder = new ContainerBuilder(projectDir: __DIR__);
$builder->scan(__DIR__ . '/src');
$container = $builder->build();
Шаг 3: Получите и используйте сервис
$userService = $container->get(App\UserService::class);
$userService->register('user@example.com');
Wirebox автоматически разрешает Mailer как зависимость UserService — ручная настройка не нужна.
Как работает автовайринг
Когда вы вызываете $container->get(UserService::class), Wirebox:
- Анализирует конструктор
UserServiceчерез рефлексию - Видит, что нужен экземпляр
Mailer - Рекурсивно разрешает
Mailer(создаёт, если нужно) - Передаёт его в конструктор
UserService - Возвращает полностью собранный
UserService
Всё происходит автоматически. Никаких файлов конфигурации и ручных привязок.
По умолчанию все сервисы — синглтоны: при каждом вызове get() возвращается один и тот же экземпляр. Используйте атрибут #[Transient], чтобы получать новый экземпляр каждый раз.
Работа с интерфейсами
Если ваш код зависит от интерфейсов, Wirebox автоматически привяжет их, если есть ровно одна реализация:
// src/LoggerInterface.php
namespace App;
interface LoggerInterface
{
public function log(string $message): void;
}
// src/FileLogger.php
namespace App;
class FileLogger implements LoggerInterface
{
public function log(string $message): void
{
file_put_contents('/var/log/app.log', $message . "\n", FILE_APPEND);
}
}
// src/OrderService.php
namespace App;
class OrderService
{
public function __construct(
private LoggerInterface $logger,
) {
}
}
Поскольку FileLogger — единственная реализация LoggerInterface в отсканированной директории, Wirebox привяжет интерфейс автоматически:
$builder->scan(__DIR__ . '/src');
$container = $builder->build();
$orderService = $container->get(App\OrderService::class);
// LoggerInterface автоматически привязан к FileLogger
Если реализаций несколько, нужна явная привязка:
$builder->bind(App\LoggerInterface::class, App\FileLogger::class);
Переменные окружения
Создайте файл .env в корне проекта:
DB_HOST=localhost
DB_PORT=5432
APP_DEBUG=true
Используйте атрибут #[Param] для инъекции переменных окружения:
use AsceticSoft\Wirebox\Attribute\Param;
class DatabaseService
{
public function __construct(
#[Param('DB_HOST')] private string $host,
#[Param('DB_PORT')] private int $port,
) {
}
}
Или определите параметры через билдер:
$builder->parameter('db.host', '%env(DB_HOST)%');
$builder->parameter('db.port', '%env(int:DB_PORT)%');
Полный пример bootstrap
<?php
// bootstrap.php
use AsceticSoft\Wirebox\ContainerBuilder;
require_once __DIR__ . '/vendor/autoload.php';
$builder = new ContainerBuilder(projectDir: __DIR__);
// Исключаем не-сервисные классы
$builder->exclude('Entity/*');
$builder->exclude('Migration/*');
// Автоматическая регистрация всех классов в src/
$builder->scan(__DIR__ . '/src');
// Явные привязки для неоднозначных интерфейсов
$builder->bind(LoggerInterface::class, FileLogger::class);
$builder->bind(CacheInterface::class, RedisCache::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->register(PDO::class, function ($c) {
return new PDO(
sprintf('mysql:host=%s;port=%d;dbname=app',
$c->getParameter('db.host'),
$c->getParameter('db.port'),
),
);
});
// Собираем и запускаем
$container = $builder->build();
$app = $container->get(App\Kernel::class);
$app->run();
Что дальше?
- Конфигурация — сканирование директорий, привязки, фабрики и fluent API
- Атрибуты — полный справочник по всем PHP-атрибутам
- Переменные окружения — dotenv, приоритеты и приведение типов
- Компилируемый контейнер — оптимизация для продакшена
- Продвинутые возможности — автоконфигурация, теги, ленивые прокси и другое