Внедрение в свойства и методы
Внедрение через конструктор — вариант по умолчанию, но иногда его нельзя использовать:
конструктором владеет базовый класс, или вы хотите разрешить зависимость лениво. Это
покрывает внедрение в свойства через #[Autowired] / #[Inject], а call() внедряет
параметры метода при его вызове.
Внедрение по типу через #[Autowired]
Поставьте #[Autowired] на свойство, и контейнер разрешит его по объявленному типу свойства
после конструирования объекта. Свойство не обязано быть публичным.
<?php
use Flytachi\Winter\DI\Attribute\Autowired;
class SyncCommand extends BaseCommand
{
#[Autowired]
private UserService $userService;
#[Autowired]
private CacheInterface $cache;
public function handle(): void
{
$this->userService->sync();
}
}Внедрение в свойства выполняется автоматически во время make(), сразу после конструктора.
Прибегайте к нему, когда конструктор не ваш, чтобы его менять — иначе предпочитайте параметры
конструктора.
Интерфейсам всё ещё нужна привязка
#[Autowired] private CacheInterface $cache разрешится, только если у CacheInterface есть
привязка — автовайринг не выберет реализацию сам. Привяжите его в
провайдере или зарегистрируйте
фабрику contextual() для пер-потребительских
экземпляров.
Внедрение конкретного класса или именованного значения через #[Inject]
#[Autowired] всегда разрешает по объявленному типу. #[Inject] это переопределяет — внедрить
конкретную реализацию или именованное значение, у которого нет осмысленного типа.
use Flytachi\Winter\DI\Attribute\Inject;
class ReportService
{
// конкретная реализация, игнорируя глобальную привязку CacheInterface
#[Inject(FileCache::class)]
private CacheInterface $cache;
// именованный скаляр, зарегистрированный через $container->set('config.timeout', 30)
#[Inject('config.timeout')]
private int $timeout;
}То же работает на параметрах конструктора — переопределите проводку для одного аргумента, не трогая глобальные привязки:
class UserService
{
public function __construct(
private CacheInterface $primary, // глобальная привязка → напр. RedisCache
#[Inject(FileCache::class)] private CacheInterface $fallback, // локальное переопределение
#[Inject('config.timeout')] private int $timeout, // именованное значение
) {}
}Autowired против Inject
#[Autowired] = разрешить по объявленному типу (явная метка внедрения по типу).
#[Inject(X::class)] = внедрить конкретный класс. #[Inject('key')] = внедрить именованное
значение, заданное через set(). Пустой #[Inject] без аргумента ведёт себя ровно как
#[Autowired].
Вызов метода через call()
call() вызывает метод или замыкание и разрешает его параметры из контейнера. Это точка
интеграции для контроллеров, команд и задач — метод объявляет, что ему нужно, а контейнер это
предоставляет.
// [class-string, method] — сначала разрешается класс, затем вызывается метод
$container->call([UserController::class, 'index']);
// [object, method] — использовать существующий экземпляр
$container->call([$controller, 'store']);
// замыкание — разрешается каждый типизированный параметр
$container->call(fn(UserService $s, AuthContext $a) => $s->current($a->user()));Передавайте runtime-значения, которые контейнер не может автовайрить (id, размеры, данные запроса), через overrides, по имени параметра:
class ImportJob
{
public function run(UserService $service, int $chunkSize): void { /* ... */ }
}
// $service автовайрится; $chunkSize приходит из override
$container->call([ImportJob::class, 'run'], ['chunkSize' => 500]);Тот же массив overrides работает у make() для параметров конструктора:
$job = $container->make(ImportJob::class, ['chunkSize' => 500]);Overrides обходят кэш синглтона
Передача массива overrides всегда строит свежий экземпляр — результат не читается из кэша
singleton/request и не пишется в него, поскольку переопределённый объект не «канонический».
Вызовите make() без overrides, чтобы получить общий экземпляр.
Связанное
- Разрыв циклических зависимостей — добавьте
#[Lazy] - Логгер на потребителя — внедрение по типу, подстраивающееся под потребителя
- Атрибуты — полный справочник по атрибутам
- Справочник API —
make()/call()и их overrides