Scope’ы
Scope определяет, как долго живёт разрешённый экземпляр и является ли он общим. Их три:
singleton, transient и request. Класс выбирает один атрибутом или привязкой; по
умолчанию — transient.
Три scope’а
| Scope | Идентичность | Кэшируется | Задаётся |
|---|---|---|---|
singleton |
один на процесс | да, после первого make() |
#[Singleton] · singleton() |
transient |
новый при каждом разрешении | нет | #[Transient] · bind() · transient() · (по умолчанию) |
request |
один на запрос / корутину | на запрос | #[Request] · request() |
singleton
Создаётся при первом make(), кэшируется в контейнере, возвращается при каждом последующем
вызове.
Для stateless-сервисов — репозиториев, фабрик, пулов соединений, читателей конфигурации. Избегать для классов с пер-запросным состоянием; оно утечёт между запросами под Swoole.
transient
Без кэширования — каждый make() / внедрение возвращает свежий объект. Это вариант по
умолчанию, когда у класса нет scope-атрибута и ручной привязки.
Для объектов с состоянием, которые не должны быть общими — билдеров запросов, form-объектов, DTO, unit of work.
request
Один экземпляр на HTTP-запрос, в зависимости от рантайма:
| Рантайм | Поведение |
|---|---|
| Swoole | Хранится в Coroutine::getContext()['__di'] — полностью изолирован по корутинам. Каждый параллельный запрос получает свой экземпляр, очищается по завершении корутины. |
| FPM | Эквивалентно singleton — один запрос = один процесс, поэтому кэш на уровне процесса корректен. |
| CLI | Эквивалентно singleton — одна команда = один процесс. |
request-scope — единственное место, где важен ext-swoole; см.
Request-scope и Swoole.
Приоритет
Ручная регистрация всегда переопределяет scope-атрибут класса — побеждает последняя привязка.
#[Singleton]
class UserService {}
// Переопределить в transient для конкретного контекста (напр. тестов)
$c->transient(UserService::class);
// → UserService теперь transient, независимо от #[Singleton]Overrides полностью обходят кэш
make($abstract, $overrides) с непустым массивом $overrides всегда строит свежий экземпляр и
не читает и не пишет кэш singleton/request — независимо от scope. Используйте make() без
overrides, чтобы получить общий экземпляр.
Матрица безопасности Swoole
Никогда не помещайте изменяемые пер-запросные данные в singleton под Swoole — они утекут
между параллельными запросами, разделяющими память воркера.
| Тип класса | Рекомендуемый scope |
|---|---|
| Пул соединений с БД | singleton |
| Репозиторий (stateless) | singleton |
| Читатель конфигурации | singleton |
| Контекст авторизации | request |
| Текущий пользователь | request |
| Unit of work | request |
| Билдер запросов | transient |
| DTO / value object | transient |
| Form-объект | transient |
Связанное
- Атрибуты — справочник по scope-атрибутам
- Request-scope и Swoole — изоляция по корутинам подробно
- Ментальная модель — почему по умолчанию
transient