Package · di

Installation & Requirements

Winter DI has a single runtime dependency and needs PHP 8.4. There are no required extensions — Swoole is optional and only affects the request scope.

System requirements

  • PHP version — 8.4 or higher. The #[Lazy] attribute injects a native PHP 8.4 lazy proxy (ReflectionClass::newLazyProxy()), which does not exist on earlier versions.
  • psr/container^2.0. Installed automatically; the container implements its ContainerInterface.
  • Operating system — portable. No POSIX or platform-specific dependency in the core.

Check your PHP version with php -v.

bash
composer require flytachi/winter-di

Optional: Swoole

ext-swoole is optional. It matters only for the request scope: under Swoole, a request-scoped instance is stored in the coroutine context so each concurrent request gets its own copy. Without Swoole (PHP-FPM or CLI) the request scope behaves like singleton — one process handles one request, so a process-level cache is already correct.

bash
# Check if Swoole is loaded
php -m | grep swoole

You do not need Swoole to use the container, autowiring, attributes, or the other two scopes. See Request scope & Swoole for details.

Bootstrap

Initialise the container once at application startup. Container::init() creates the instance and stores it as the process-wide singleton so it can be reached anywhere via Container::getInstance().

bootstrap.php
<?php

require 'vendor/autoload.php';

use Flytachi\Winter\DI\Container;
use Flytachi\Winter\DI\Scanner;
use Flytachi\Winter\DI\Collector\DICollector;

// 1. Create the container
$container = Container::init();

// 2. Auto-register annotated classes (#[Singleton], #[Request], #[Transient])
Scanner::run(__DIR__ . '/src', cache: __DIR__ . '/var/cache/di.php')
  ->collect(new DICollector($container))
  ->execute();

// 3. Register interface bindings and factories
$container->register(AppServiceProvider::class);

The three steps are independent — you can skip the Scanner step and register everything manually, or skip providers if you only rely on attributes and autowiring.

What each step gives you

Step 2 (Scanner + DICollector) discovers classes carrying a scope attribute and binds them — see Scanning & autodiscovery. Step 3 (ServiceProvider) is where interface → implementation mappings and factory closures live — see Service providers.

Next steps