Атрибуты
Полная поверхность атрибутов. Scope-атрибуты ставятся на классы; атрибуты внедрения — на
свойства и параметры конструктора. Все они final readonly.
Кратко
| Атрибут | Цель | Аргумент | Назначение |
|---|---|---|---|
#[Singleton] |
класс | — | Один общий экземпляр на процесс. |
#[Request] |
класс | — | Один экземпляр на запрос / корутину. |
#[Transient] |
класс | — | Новый экземпляр при каждом разрешении (по умолчанию). |
#[Autowired] |
свойство, параметр | — | Внедрить по объявленному типу. |
#[Inject] |
свойство, параметр | ?string $id = null |
Внедрить конкретный класс или именованное значение. |
#[Lazy] |
свойство, параметр | — | Внедрить отложенный proxy, разрешаемый при первом использовании. |
Пространство имён: Flytachi\Winter\DI\Attribute\.
Scope-атрибуты
Задают время жизни класса. Читаются DICollector во время сканирования или контейнером при
первом make(), если класс не привязан вручную. Ручная привязка всегда переопределяет
атрибут. Полная семантика — на странице Scope’ы.
#[Singleton]
use Flytachi\Winter\DI\Attribute\Singleton;
#[Singleton]
class UserRepository
{
public function __construct(private DatabaseConnection $db) {}
}Один экземпляр на время жизни контейнера (процесса). Эквивалентно
$container->singleton(UserRepository::class). Для stateless-сервисов. Не для
пер-запросного состояния под Swoole — используйте #[Request].
#[Request]
use Flytachi\Winter\DI\Attribute\Request;
#[Request]
class AuthContext
{
private ?User $user = null;
}Один экземпляр на HTTP-запрос / корутину. Под Swoole изолируется через
Coroutine::getContext(); под FPM / CLI эквивалентно #[Singleton] (один процесс = один
запрос). Для пер-запросного состояния.
#[Transient]
use Flytachi\Winter\DI\Attribute\Transient;
#[Transient]
class QueryBuilder
{
private array $clauses = [];
}Новый экземпляр при каждом make() / внедрении. Это уже поведение по умолчанию, когда атрибута
нет — #[Transient] просто делает намерение явным.
Атрибуты внедрения
Отмечают, где и как предоставляется зависимость. На свойстве внедрение выполняется
автоматически после конструктора во время make(); свойство не обязано быть публичным.
#[Autowired]
use Flytachi\Winter\DI\Attribute\Autowired;
class UserController
{
#[Autowired]
private UserService $service;
public function __construct(
#[Autowired] private CacheInterface $cache,
) {}
}Разрешает зависимость по объявленному PHP-типу. Эквивалентно #[Inject] без аргумента —
явная метка внедрения по типу. Интерфейсу всё равно нужна привязка, чтобы это разрешилось.
#[Inject]
use Flytachi\Winter\DI\Attribute\Inject;
// #[Inject(?string $id = null)]Переопределяет автовайринг для одного параметра или свойства.
Значение $id |
Поведение |
|---|---|
null (по умолчанию) |
Разрешить по объявленному PHP-типу — как #[Autowired]. |
строка FQCN, напр. #[Inject(FileCache::class)] |
Внедрить этот конкретный класс, обходя глобальную привязку объявленного типа. |
именованный ключ, напр. #[Inject('config.timeout')] |
Внедрить скаляр / заранее построенное значение, заданное через Container::set(). |
class UserService
{
public function __construct(
private CacheInterface $primary, // глобальная привязка
#[Inject(FileCache::class)] private CacheInterface $fallback, // конкретный класс
#[Inject('config.timeout')] private int $timeout, // именованное значение
) {}
}#[Lazy]
use Flytachi\Winter\DI\Attribute\Lazy;
class SmsSendService
{
#[Lazy]
private FakeSendService $peer; // нативный proxy PHP 8.4; разрешается при первом использовании
}Внедряет нативный ленивый proxy PHP 8.4 (ReflectionClass::newLazyProxy()) вместо
немедленного разрешения. Реальный экземпляр строится из контейнера при первом обращении —
механизм разрыва циклических зависимостей.
- Работает на свойствах и параметрах конструктора; сочетается с
#[Autowired]/#[Inject]. - Проксируемый тип должен быть конкретным классом. Для интерфейса укажите конкретный:
#[Inject(SmsSendService::class), Lazy]. Пустой#[Lazy]на интерфейсе или абстрактном классе бросаетContainerException. - Proxy совместим по типу с реальным классом и остаётся неинициализированным до первого использования.
Внутренности — в Ленивых proxy.
Приоритет
Для одной зависимости контейнер применяет первое подходящее правило:
- Override у
make()/call()по имени параметра. #[Inject]— явный$idили объявленный тип, когда$idравенnull.#[Autowired]— объявленный тип.- Автовайринг — объявленный тип, со значением по умолчанию параметра как запасным вариантом, если тип разрешить не удалось и значение по умолчанию есть.
#[Lazy] ортогонален: он меняет когда строится выбранная зависимость (откладывает до первого
использования), а не какая именно.