Circular Dependencies
Detection
A cycle fails at once with ContainerException and the whole resolution chain:
php
final class A { public function __construct(public B $b) {} }
final class B { public function __construct(public A $a) {} }
$container->get(A::class);
// ContainerException: Circular dependency detected: A -> B -> AThe same applies to recursive bindings (bind(A::class, B::class) with bind(B::class, A::class)) and to a factory that calls $c->get() on its own id.
Breaking a Cycle
To break a genuine cycle, make one participant lazy — in the container with lazy(), or at the exact injection point with #[Lazy]. The lazy side is injected as a proxy, so the other constructor completes without resolving it again:
php
$container->lazy(B::class); // B is always a proxy
// — or, only this edge —
final class A { public function __construct(#[Lazy] public B $b) {} }
$a = $container->get(A::class); // resolves; $a->b is a lazy proxy, and $a->b->a === $aWhen the proxy is first used, it builds B, which receives the A instance already cached. See Lazy Services for what a proxy can and cannot do.