Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Управление жизненным циклом зависимостей

Библиотека предоставляет три типа жизненного цикла для зависимостей, что особенно полезно в долгоживущих процессах:

  • Приложениях на RoadRunner или FrankenPHP
  • Фоновых workers
  • В консольных командах, обрабатывающих множество задач

Вы можете управлять жизненным циклом любых зависимостей: entries, params, alias и autowiring.

📋 Демонстрация разницы.

<?php
declare(strict_types=1);

namespace App;

class Scoped {}
class Singleton {}
class Factory {}

new \Cekta\DI\ContainerBuilder(
    entries: [
        \App\Scoped::class,
        \App\Singleton::class,
        \App\Factory::class,
    ],
    fqcn: 'App\\Container',
    singletons: [\App\Singleton::class],   // Singleton-зависимости
    factories: [\App\Factory::class],      // Factory-зависимости
    // Scoped-зависимости не указываются явно (используются по умолчанию)
)->build();

index.php - Usage (Использование)

<?php
declare(strict_types=1);

namespace App;

function testLifecycle(string $className) {
    $container1 = new \App\Container();
    $container2 = new \App\Container();
    
    $a = $container1->get($className);
    $b = $container1->get($className);  // Второй запрос к тому же контейнеру
    $c = $container2->get($className);  // Запрос к другому контейнеру
    
    echo "Внутри одного контейнера: " . ($a === $b ? "одинаковый" : "разный") . "\n";
    echo "Между разными контейнерами: " . ($a === $c ? "одинаковый" : "разный") . "\n";
    echo "---\n";
}

echo "Scoped (по умолчанию):\n";
testLifecycle(Scoped::class);

echo "Singleton:\n";
testLifecycle(Singleton::class);

echo "Factory:\n";
testLifecycle(Factory::class);

Результат:

Scoped (по умолчанию):
Внутри одного контейнера: одинаковый
Между разными контейнерами: разный
---
Singleton:
Внутри одного контейнера: одинаковый
Между разными контейнерами: одинаковый
---
Factory:
Внутри одного контейнера: разный
Между разными контейнерами: разный

🎯 Сравнение жизненных циклов

ТипВнутри одного контейнераМежду разными контейнерамиКогда использовать
Scoped ⭐Один объектРазные объектыОбработка запросов, пользовательские сессии
SingletonОдин объектОдин объектКонфигурация, подключения к БД, кеши
FactoryРазные объектыРазные объектыStateless-сервисы, DTO, временные данные

⚠️ Важные замечания

  1. Scoped по умолчанию - если не указан другой тип, используется Scoped
  2. Конфликты приоритетов - нельзя указать один класс одновременно как Singleton и Factory
  3. Производительность - Factory создаёт наибольшую нагрузку, Singleton - наименьшую
  4. Потокобезопасность - Singleton должен быть потоко-безопасным в многопоточных средах

🚀 Пример для долгоживущего приложения

<?php
new \Cekta\DI\Compiler(
    entries: [
        HttpController::class,
        UserRepository::class,
        EmailService::class,
    ],
    singletons: [
        Database::class,           // Одно подключение
        RedisCache::class,         // Общий кеш
        Config::class,             // Конфигурация
    ],
    factories: [
        HttpRequest::class,        // Новый для каждого запроса
        UserSession::class,        // Новый для каждого пользователя
    ],
);

Правильное управление жизненным циклом позволяет:

  • Экономить ресурсы (Singleton)
  • Изолировать данные (Scoped)
  • Предотвращать утечки памяти (Factory)
  • Легко масштабировать приложение