Skip to content
docsv0.1.0

DIContainer

Reflection-autowiring dependency injection container. This is the maximal implementation of {@see DIContainerInterface}: the interface only guarantees resolution of identifiers explicitly registered via {@see registerService()} and documents auto-resolution of {@see get()} and {@see has()} as a MAY, not a MUST. This class exercises that MAY — it additionally auto-wires and caches unregistered-but-existing classes. Concretely, beyond the interface's baseline, this implementation guarantees: - {@see get()} and {@see has()} auto-resolve any existing, non-abstract, non-interface class whose constructor dependencies are themselves resolvable (recursively) — not just identifiers registered via {@see registerService()}. - Auto-resolved classes are cached as singletons on first resolution: subsequent {@see get()} calls for the same identifier return the same instance, unless {@see resolve()} was called directly with `$singleton = false`. - {@see resolve()} detects circular dependency chains (A needs B needs A, directly or transitively) and throws {@see CircularDependencyException} with the full chain of class names that produced the cycle. - {@see tryGet()} never throws: it returns `null` for anything that is not registered and cannot be auto-resolved, instead of propagating {@see ServiceNotFoundException} or {@see ContainerResolutionException}. - Classes found to be non-resolvable (interfaces, abstract classes, classes with unresolvable constructor parameters) are cached as such, so repeated lookups do not re-run reflection.

DIContainer::__construct()

public function __construct():

DIContainer::getContainer()

public function getContainer(): Psr\Container\ContainerInterface

DIContainer::registerService()

public function registerService(string $id, object|string $classOrInstance): void

Registers a service under the given identifier. A class-string is registered on the underlying `ContainerBuilder` as a public service definition (resolved and instantiated on first `get()`); an object is set directly, bypassing definition-based resolution entirely. Either way, this takes precedence over on-demand auto-wiring via {@see resolve()} for the same identifier.

Parameters

Parameters of registerService()
NameTypeDescription
$idstringService identifier (usually FQCN)
$classOrInstance(string | object)A class name to register for lazy resolution, or an already-built instance

DIContainer::compileContainer()

public function compileContainer(): void

Compiles the underlying container, freezing its service definitions. Delegates to Symfony `ContainerBuilder::compile()`: runs the builder's compiler passes and locks the definitions in place. Auto-wired services resolved before this call remain cached as singletons; explicit {@see registerService()} calls made after compiling still work (this container does not otherwise restrict post-compile mutation), but compiling is meant to mark the point past which the service graph is considered final.

DIContainer::get()

public function get(string $id): ?mixed

Get a service from the container. If the service is not registered but the class exists, it will be auto-resolved and registered as a singleton.

Parameters

Parameters of get()
NameTypeDescription
$idstringService identifier (usually FQCN)

Returns

Service instance

Throws

ServiceNotFoundException If no entry exists for $id and it cannot be auto-resolved.

ContainerResolutionException If auto-resolution is attempted but fails.

DIContainer::has()

public function has(string $id): bool

Checks whether an identifier is resolvable. True for anything registered via {@see registerService()}. For an unregistered identifier, this implementation additionally returns true when it names an existing, non-abstract, non-interface class whose constructor dependencies are (recursively) resolvable — the auto-wiring guarantee documented on the class. The check never instantiates anything; it walks constructor parameter types to decide resolvability.

Parameters

Parameters of has()
NameTypeDescription
$idstringService identifier

Returns

True if registered or auto-resolvable

DIContainer::tryGet()

public function tryGet(string $id): ?mixed

Get a service or return null if not available.

Parameters

Parameters of tryGet()
NameTypeDescription
$idstringService identifier

Returns

Service instance or null

DIContainer::resolve()

public function resolve(string $className, bool $singleton = true): ?mixed

Resolve a class with auto-wiring.

Parameters

Parameters of resolve()
NameTypeDescription
$classNamestringFully qualified class name
$singletonboolRegister as singleton (default: true)

Returns

Class instance

Throws

CircularDependencyException If resolving $className re-enters itself via its own dependency chain.

ContainerResolutionException If the class does not exist, is abstract/an interface, or a constructor dependency cannot be resolved.