This package gives you two main workflows:
- register a binding and resolve a shared instance with
get() - create a fresh object graph on demand with
create()orautowire()
Use register() when application code depends on an interface or abstract class name.
use App\Contracts\MailerInterface;
use App\Services\SmtpMailer;
use Quantum\Di\Di;
Di::register(SmtpMailer::class, MailerInterface::class);
$mailer = Di::get(MailerInterface::class);get() returns the same shared instance on later calls for MailerInterface::class.
Use create() when you want a fresh instance and do not need shared caching.
use App\Services\ReportBuilder;
use Quantum\Di\Di;
$builderA = Di::create(ReportBuilder::class);
$builderB = Di::create(ReportBuilder::class);$builderA and $builderB are different objects.
Because create() auto-registers missing classes against themselves, this works even when ReportBuilder was not registered earlier.
That self-registration persists in the container registry, so a later Di::get(ReportBuilder::class) call will succeed and start returning a shared instance for that class key.
Use set() when you already have an object and want the container to return it later.
use App\Contracts\ClockInterface;
use App\Testing\FakeClock;
use Quantum\Di\Di;
Di::set(ClockInterface::class, new FakeClock());
$clock = Di::get(ClockInterface::class);The current implementation has two gotchas:
- you cannot call
set()twice for the same abstract once an instance already exists - the abstract key must be a real class or interface name
Also, set() seeds only the runtime container entry. If you clear the container with Di::resetContainer(), the seeded object is removed and future get() calls fall back to the registered concrete binding.
autowire() prepares the arguments for a closure or array callable.
use App\Contracts\MailerInterface;
use Quantum\Di\Di;
$args = Di::autowire(
function (MailerInterface $mailer, string $subject = 'Hello') {
return [$mailer, $subject];
},
['Weekly digest']
);The returned $args array contains the resolved mailer instance plus the manual subject argument.
You still invoke the callable yourself:
$result = (function (MailerInterface $mailer, string $subject = 'Hello') {
return [$mailer, $subject];
})(...$args);If you pass a class-string array callable such as [Handler::class, 'run'], autowire() only reflects the method signature. It does not create a Handler instance or perform the method call for you.
Constructor and callable parameters are resolved in a strict order.
If a parameter type is registered in the container, that dependency is injected before any manual argument is consumed.
If the type is not registered but names an instantiable class, the container creates it automatically.
For non-class parameters, manual $args are consumed with array_shift().
$args = Di::autowire(
function (string $name, int $count) {},
['cache', 3]
);The resolver does not match by parameter name.
If a parameter is typed as array, it receives the full remaining manual argument list.
$args = Di::autowire(
function (array $payload) {},
['a' => 1, 'b' => 2]
);In the current implementation, $payload becomes the remaining $args array exactly as held by the resolver.
If class graphs reference each other in a loop, resolution fails with DiException::circularDependency(...).
Example shape:
Adepends onBBdepends onA
The exception message includes the chain that was being resolved.
Use:
Di::resetContainer()to clear shared instances but keep bindingsDi::reset()to clear both bindings and shared instances
reset() is the stronger reset and is usually the safer option for test isolation.
get()fails for unknown abstractions; it does not auto-register them.autowire()does not accept string callables or invokable objects.- Missing required scalar parameters can fall through as
nulland fail later when PHP enforces the signature. - Shared instances are container-scoped. If the app context changes containers, later
Di::...calls follow the new container.