Skip to content

Feature Factories

github-actions[bot] edited this page Jul 8, 2026 · 1 revision

🏭 Фабрики и singleton

← Возможности · Главная · Сравнение

Фабрика — callable, создающий сервис лениво. По умолчанию результат кэшируется как singleton: один экземпляр на весь контейнер.

Принцип работы

set($id, $factory) кладёт callable в definitions. При первом get($id) контейнер вызывает фабрику (передавая сам контейнер, чтобы фабрика могла достать зависимости), сохраняет результат в resolved и возвращает. Все последующие get($id) возвращают закэшированный экземпляр без повторного вызова фабрики.

$c->set(PaymentGateway::class, function (Container $c) {
    return new PaymentGateway(
        $c->get(HttpClient::class),
        $c->get('config.stripe_key'),
    );
});

$a = $c->get(PaymentGateway::class);
$b = $c->get(PaymentGateway::class);
$a === $b; // true — singleton

Готовый объект тоже можно зарегистрировать (set($id, $object)) — тогда он просто отдаётся как есть.

Плюсы

  • Ленивость: сервис создаётся только при первом обращении — пустой контейнер лёгкий, старт приложения быстрый.
  • Полный контроль: в фабрике можно собрать сложную инициализацию, которую autowiring не покроет.
  • Singleton по умолчанию — то, что нужно для stateless-сервисов (клиенты, репозитории).

Минусы

  • Фабрику надо писать руками — для простых классов лишний boilerplate (используйте autowiring).
  • Singleton хранит состояние между вызовами — опасно для изменяемых объектов в долгоживущих процессах (worker, Swoole).

✅ Рекомендуется

  • Держать фабрики «тонкими»: только сборка зависимостей, без бизнес-логики и побочных эффектов.
  • Для stateless-сервисов — singleton (по умолчанию); для сервисов с состоянием запроса — make() или scope.
  • Типизировать возвращаемое значение фабрики (fn (): PaymentGateway => …) — читаемость и статанализ.

❌ Антипаттерны

  • Выполнять в фабрике тяжёлые side-effects (запросы к БД, HTTP) — фабрика должна строить, а не работать.
  • Кэшировать как singleton объект, зависящий от текущего запроса/пользователя, в долгоживущем процессе.

Аналоги в других контейнерах

Контейнер Аналог
PHP-DI factory() / автоматический singleton; factory()->parameter()
Symfony определение сервиса shared: true (по умолчанию)
Laravel bind() (новый экземпляр) vs singleton() (кэш)
Pimple $c['id'] = fn () => … (singleton); $c->factory() для не-singleton
Nette сервисы в конфиге — singleton по умолчанию

Паритет: фабрики + singleton-кэш есть во всех контейнерах.

См. также: Прототипы · Smart cache / TTL.

Clone this wiki locally