> For the complete documentation index, see [llms.txt](https://quantumphp.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://quantumphp.gitbook.io/docs/packages/di/overview.md).

# Overview

The Di package is Quantum's runtime dependency injection container. It keeps class bindings in a registry, resolves constructor dependencies with reflection, and optionally caches shared instances for the current app context.

The package is built from three classes:

* `Quantum\Di\Di` is the static facade.
* `Quantum\Di\DiContainer` performs registration, resolution, and instance caching.
* `Quantum\Di\DiRegistry` stores validated abstract-to-concrete bindings.

## Entry points

### `Di` facade

`Quantum\Di\Di` does not keep its own global container. Every static call is forwarded to the container returned by `App::getContext()->getContainer()`.

That means the static API is only a facade over the current app context. If the app context swaps containers, later `Di::...` calls will use the new container.

### `DiContainer`

`DiContainer` is the real runtime object. It exposes the package API:

* `registerDependencies()`
* `register()`
* `isRegistered()`
* `has()`
* `set()`
* `get()`
* `create()`
* `autowire()`
* `reset()`
* `resetContainer()`

## Registration model

### `register(string $concrete, ?string $abstract = null)`

`register()` stores a binding in `DiRegistry`.

* With only `$concrete`, the class is registered against itself.
* With both arguments, the abstract key points to the concrete class.
* The concrete class must exist and be instantiable.
* When an abstract key is provided, it must be an existing class or interface.
* Re-registering the same abstract key throws `DiException::dependencyAlreadyRegistered(...)`.

### `registerDependencies(array $dependencies)`

`registerDependencies()` iterates the input map and only registers keys that are not already present. Existing bindings are skipped instead of replaced.

## Resolution model

### Shared instances: `get()`

`get()` requires the dependency to be registered first. It then resolves the binding and caches the created object under the abstract key.

Repeated `get()` calls for the same abstract return the same instance for that container.

### Fresh instances: `create()`

`create()` always returns a newly instantiated object.

If the dependency is not registered yet, `create()` first registers it against itself and then resolves it without caching the result in the container.

### Manual instances: `set()`

`set()` inserts an already-built object into the container.

Important rules from the current implementation:

* The abstract must be an existing class or interface.
* The instance must satisfy `is_a($instance, $abstract)`.
* If the container already has an instance for that abstract, `set()` always throws, regardless of the `$override` flag.
* If the abstract is not registered yet, `set()` auto-registers the instance class against that abstract.
* `$override = false` only blocks inserting an instance when a registry binding already exists.
* With the default `$override = true`, `set()` may add a container instance even when a registry binding already points somewhere else.

## Autowiring behavior

`autowire()` resolves parameters for a callable and returns the argument list. It does not invoke the callable.

Supported callable forms are limited to:

* closures
* array callables such as `[$object, 'method']` or `[ClassName::class, 'method']`

Anything else throws `DiException::invalidCallable(...)`.

Parameter resolution follows this order:

1. If the parameter type is registered, return `get($type)`.
2. Otherwise, if the type names an instantiable class, return `create($type)`.
3. If the parameter type is `array`, return the entire remaining `$args` array.
4. If manual `$args` still contain values, shift and return the next one.
5. Otherwise return the parameter default value when available.
6. Otherwise return `null`.

This has a few practical consequences:

* registered class dependencies are shared
* unregistered instantiable class dependencies are created fresh
* scalar parameters are positional only
* missing required scalar parameters become `null`, which can still fail later when PHP enforces the callable or constructor signature

## Circular dependency protection

During `get()` and `create()`, the container tracks the abstract keys it is currently resolving.

If resolution re-enters an abstract that is already in progress, the package throws `DiException::circularDependency(...)` with a chain such as:

```
FooInterface -> BarService -> FooInterface
```

## Reset behavior

* `resetContainer()` clears cached instances and the in-progress resolution map.
* `reset()` clears both the registry bindings and the cached instances.

Use `reset()` only when you want a fully empty container state.

## Important constraints

* The package only resolves constructor injection; there is no factory binding API in this package.
* `has()` checks cached instances only. It does not tell you whether a dependency is registered.
* `isRegistered()` checks registry bindings only. It does not tell you whether an instance has been created.
* `Di::__callStatic()` throws `DiException::invalidCallable($method)` when the current container does not implement the requested method.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://quantumphp.gitbook.io/docs/packages/di/overview.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
