Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Di Laravel Package

aura/di

Aura.Di is a serializable dependency injection container for PHP 8+ supporting constructor and setter injection, interface and trait awareness, configuration inheritance, and PSR-11 compliance. It has no external implementation dependencies and installs via Composer as aura/di.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer; the package is PSR-4 autoloadable and requires PHP 8.0+:

composer require aura/di

On 5.x, the container constructor requires a Resolver (this changed from 4.x, where you built a container with an injection factory). The smallest useful setup is:

use Aura\Di\Container;
use Aura\Di\Resolver;

$di = new Container(new Resolver());

$di->set('clock', $di->lazyNew(Clock::class));

$clock = $di->get('clock');   // PSR-11 get()
$di->has('clock');            // PSR-11 has()

Look first at docs/index.md and its linked pages, then at changelog/5.0.0.md. The 5.0 changelog is the important one: it introduces attribute-driven configuration, class scanning, and a compile step, and it changes the constructor contract. If you are coming from 4.x or earlier, read docs/migrating.md before copying old snippets.

The first real use case is not a one-off $di->get() call, but a config class. Implement Aura\Di\ContainerConfigInterface::define(Container $di) and keep all wiring for one module in that class. That scales far better than scattering set() calls, and it mirrors the Laravel service-provider habit without relying on Laravel's container.

Implementation Patterns

Config classes as the unit of composition. Each module gets a ContainerConfigInterface implementation. Use ContainerBuilder or ConfigCollection to combine several configs into one container. This is the closest Aura equivalent to Laravel service providers, except there is no separate boot() phase and no deferred-provider machinery: define() is where all wiring happens.

Use params, setters, and values deliberately. Constructor arguments go in $di->params, setter injection in $di->setters, and shared scalar/config values in $di->values. Prefer named parameters ('$dsn') over positional indexes unless you are intentionally overriding. For a consumer class, define only what cannot be inferred:

$di->params[Database::class] = [
    'dsn' => $di->lazyValue('db.dsn'),
];

$di->setters[LoggerAware::class] = [
    'setLogger' => $di->lazyGet('logger'),
];

Bind interfaces with lazyGet, not direct instances. Keep the interface name as the service key and inject lazies into consumers. That gives you a single place to swap implementations and keeps construction deferred until the consuming service is actually resolved.

Lean on auto-resolution for leaves, be explicit for edges. Aura will auto-resolve class/interface typehints in constructor parameters, but it will not invent scalar values (or arrays and nulls since 3.x). Treat autowiring as a convenience for simple value objects and repositories, and explicitly configure anything with a DSN, key, path, or feature flag. This is the opposite of Laravel's “bind only when you need to” default; here the explicit config is the design.

Master the lazy family. lazyNew, lazyGet, lazyValue, lazyInclude, lazyRequire, lazyArray, lazyCallable, and (5.x) lazyLazy are the tools for deferring resolution. They matter for two reasons: they avoid premature instantiation, and they avoid auto-locking the container while you are still configuring it. Returning a new instance each time versus resolving a shared service is controlled by whether you use newInstance()/lazyNew or a named service via get/lazyGet.

Use the 5.x attribute + compile flow for larger apps. Mark classes and namespaces with #[Blueprint] and #[BlueprintNamespace], use #[Service], #[Instance], and #[Value] for injection, and scan with the bin/auradi executable. For production, compile the container so reflection and class-map generation are done ahead of time rather than on every request. ContainerCompileInterface lets your own config classes hook into compilation if you need custom post-processing.

Integrate with Laravel by keeping ownership clear. Aura is a standalone PSR-11 container, not a drop-in Laravel container replacement. In a Laravel app, build the Aura container inside a service provider and expose the services you need to Laravel via $this->app->instance() or thin bindings. Alternatively, use Aura only inside a framework-agnostic package and let Laravel's container handle the application layer. Do not let both containers independently construct the same stateful service.

Test configs, not just classes. Use AbstractContainerConfigTest and the container assertion traits to verify that each config class defines the expected services, params, and setters. This catches wiring regressions that normal unit tests miss because they never exercise the container.

Gotchas and Tips

  • Auto-locking bites during configuration. In Aura, get() and newInstance() lock the container. If you resolve a service and then try to add params or setters, you will get errors. Use lazy* definitions while configuring, and only resolve at the end of the bootstrap.
  • Missing scalars fail loudly. With auto-resolution disabled, an undefined constructor parameter throws MissingParam. Even with it enabled, scalars are not guessed. Define every non-class parameter explicitly.
  • Service-name typos are silent until resolution. The container is largely array-driven; has() is your friend in tests and debug tooling. If a service behaves unexpectedly, inspect the relevant config class before digging into the container internals.
  • 5.x breaks 4.x constructor code. new Container() is not enough on 5.x; pass a Resolver. The resolver also holds service instances in 5.x, which changes assumptions about where shared state lives.
  • Serialization and closures. The container can be serialized for caching, but not when it contains closures. The compiled/blueprint path exists precisely to avoid runtime reflection; use it for production rather than serializing an ad-hoc container with lazy closures.
  • Attribute scanning has prerequisites and edge cases. The scanner relies on composer/class-map-generator, and classes that error during scanning are excluded from the class map (fixed across 5.0.x). If an attribute comes from an uninstalled external package, 5.0.9 changed behavior to avoid yielding broken attribute data. Keep the scan roots correct, and do not assume every class in src/ is visible to the scanner.
  • Constructor promotion is supported, but the injection attributes must target properties. #[Service], #[Instance], and #[Value] were changed to allow promoted constructor properties. If you write a custom attribute config, implement AttributeConfigInterface and mark it with #[AttributeConfigFor] (repeatable since 5.0.5).
  • ContainerBuilder wants config class names, not instantiated configs. That has been true since 3.x and is a common source of “why isn't my config running?” confusion.
  • Contextual parameters take precedence. If you define both class-level params and contextual overrides, the more specific definition wins. Use that intentionally rather than layering conflicting configuration across several config classes.
  • Debugging path. Start with the exception type: MissingParam means configuration, not code. Then inspect $di->params, $di->setters, and $di->values for the exact class name. For compile-related failures, run the scan command manually and inspect the generated class map before blaming the runtime.
  • Extension points are narrow but real. AttributeConfigInterface for custom attribute behavior, ContainerCompileInterface for compile hooks, and the lazy classes/serialization machinery for caching. There is no Laravel-style extend()/rebinding callback API, so design extension through config-class composition rather than monkey-patching the container.
  • Set expectations around ecosystem. With a small dependent count and a documentation-first, config-heavy API, Aura.Di rewards teams that want explicit, serializable, framework-agnostic wiring. It is a poor fit if you expect Laravel's contextual binding, facades, and zero-config autowiring out of the box.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter