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

hyperf/di

Hyperf/DI is a lightweight dependency injection container for Hyperf, offering PSR-11 compatibility, annotation-based injection, AOP support, and flexible bean management for PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

hyperf/di is the standalone DI sub-package split out of hyperf/hyperf — the low star count reflects the split-repo pattern, not maturity. Check composer.json constraints against your hyperf/framework version before trusting any snippet you find.

Minimal wiring — you rarely construct the container yourself; the skeleton does it for you:

// config/container.php  (returns a PSR-11 container built from definitions)
return (new \Hyperf\Di\DefinitionSourceFactory(true))();
// bin/hyperf.php  (bootstrap: annotation scan + AOP proxy class map)
Hyperf\Di\ClassLoader::init();

Look at these three files first:

  1. config/container.php — how the container is produced.
  2. config/autoload/annotations.php — which directories are scanned (scan.paths, default BASE_PATH . '/app'), plus ignore_annotations and custom collectors.
  3. config/autoload/dependencies.php — interface→implementation bindings consumed by DefinitionSourceFactory.

First use case — resolve something and inject it:

use Hyperf\Context\ApplicationContext;
use Hyperf\Di\Annotation\Inject;

class OrderService
{
    #[Inject]
    protected PaymentGateway $gateway;      // property injection

    public function __construct(private readonly Repo $repo) {}  // constructor injection
}

// anywhere, coroutine-safe:
$svc = ApplicationContext::getContainer()->get(OrderService::class);

If that works, you already have constructor injection, annotation injection, and singleton resolution. Everything else is variation on this.

Implementation Patterns

Constructor injection is the default; #[Inject] is the escape hatch. Use constructor injection for anything you control — it's testable, explicit, and fails loudly. Reach for #[Inject] only when the framework instantiates the class for you (controllers' optional deps, listeners, aspects) or when you need lazy resolution to break a cycle. #[Inject] writes through reflection onto the property after construction, so the object must come from the container.

get() vs make() — know the difference cold.

$container->get(Foo::class);                          // shared instance, definition-resolved
$container->make(Foo::class, ['bar' => $bar]);        // always a NEW instance, named ctor args

make() is the one you want for per-request value objects, short-lived jobs, or anything where you need to pass runtime arguments by parameter name. Calling get() twice returns the same object — a frequent source of "why is my state leaking" bugs in long-running workers.

Bind interfaces in config, not in code. config/autoload/dependencies.php:

return [
    PaymentGateway::class => StripeGateway::class,
];

This is read by DefinitionSourceFactory, so it applies everywhere, including lazily resolved graph branches. Prefer it over $container->set() outside tests.

Lazy injection for cycles and heavy graphs.

#[Inject(lazy: true)]
protected ReportBuilder $builder;

You get a generated proxy (friendsofphp/proxy-manager-lts); the real object is built on first method call. This is the standard fix for A↔B constructor cycles, and it also keeps boot cheap when a dependency is expensive but rarely used. Do not rely on instanceof or serialize() against a lazy proxy — it's a subclass, and the identity check may surprise you.

AOP for cross-cutting concerns — logging, metrics, transaction wrappers, retry:

use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\Di\Annotation\Aspect;

#[Aspect]
class TimingAspect extends AbstractAspect
{
    public array $classes = [App\Service\*::class];   // wildcards supported
    public array $annotations = [App\Annotation\Timed::class];
    public int $priority = 10;

    public function process(ProceedingJoinPoint $p)
    {
        $start = microtime(true);
        try {
            return $p->process();                     // must call exactly once
        } finally {
            $this->record($p->getReflectMethod()->getName(), microtime(true) - $start);
        }
    }
}

$p->getArguments() / setArguments() let you rewrite arguments; getInstance() gives the target object. This is the feature that most distinguishes hyperf/di from a plain PSR-11 container — treat aspects as first-class design, not decoration.

Custom annotations + AnnotationCollector when you want metadata-driven behaviour (route registration, validation, permission checks):

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Timed implements AnnotationInterface
{
    public function collectClass(string $className): void
    {
        AnnotationCollector::collectClass($className, self::class, $this);
    }
    // collectMethod / collectProperty as needed
}

// later, without reflection at runtime:
$classes = AnnotationCollector::getClassesByAnnotation(Timed::class);

Register any custom collector in config/autoload/annotations.php under scan.collectors if it needs a post-scan pass (e.g. to write a cached index).

Reflection is expensive in a worker; cache it. Use Hyperf\Di\ReflectionManager::getClassReflection($class) instead of new ReflectionClass(...) in hot paths — it memoizes per-process.

Testing. Swap implementations on the container rather than mocking globals:

$container = ApplicationContext::getContainer();
$container->set(PaymentGateway::class, new FakeGateway());

Do this in setUp() and restore in tearDown(); the container is process-wide and leaks between tests otherwise.

Gotchas and Tips

new bypasses DI. new Foo() gets you AOP interception (the class loader swaps in the proxy) but not property/constructor injection. Any #[Inject] property stays uninitialized, and typed properties will throw Error: must not be accessed before initialization on first read. Resolve from the container, or inject a factory. This is the single most common runtime failure.

Scan cache staleness is the #1 debugging tax. Annotation metadata and AOP proxies live in runtime/container/. After adding an annotation, changing an aspect, editing annotations.php, or pulling new code in a container, clear it:

rm -rf runtime/container
php bin/hyperf.php di:init-proxy   # regenerate AOP proxies explicitly

Symptom of a stale cache: your new aspect silently does nothing, or an old one still fires. Set SCAN_CACHEABLE=true in production (big startup win) and remember it means the cache is now a deploy artifact — your release process must clear it.

Only scanned paths get annotations. Default is app/, so vendor classes and anything outside configured scan.paths are invisible to AnnotationCollector and to $annotations-matched aspects. If an aspect on a third-party class won't fire, this is why. Widen scan.paths deliberately — every added path costs boot time.

AOP boundaries. Final classes and final methods can't be proxied; static methods and constructors aren't advised. Methods called via parent::, self::, or from inside the same class still route through the proxy (that's the point), but closures and string callables ('Foo::bar') won't. If an aspect mysteriously skips one method, check final first.

Aspect ordering is by priority, then registration order. With multiple aspects on the same method the nesting is easy to get wrong, and there's no "correct" direction to guess — prove it once with a before/after log pair, then pin explicit priority values for every aspect that overlaps. Don't leave two aspects at the default 0 and hope.

Circular dependencies have two fixes and they aren't equivalent. #[Inject(lazy: true)] defers resolution (proxy, cheap, but every call pays a small overhead and identity checks get fuzzy); #[Inject] on a property defers the assignment to after construction (real object, no proxy). Prefer restructuring to eliminate the cycle; if you can't, pick property injection unless the dependency is genuinely expensive.

get() returns singletons. In a long-running coroutine worker, mutable state on a container-managed singleton is shared across all requests in that worker. Either keep services stateless or use make() for anything holding request-scoped data. Coroutine-local state belongs in Hyperf\Context\Context, not on the injected object.

Use ApplicationContext, not a stashed container. ApplicationContext::getContainer() is coroutine-aware and is the correct accessor inside services. Don't capture the container into a property at boot and reuse it across a Coroutine::create() boundary.

Interfaces without a binding fail late. The container throws on get(SomeInterface::class) with no definition, and if the interface is resolved deep inside a lazy branch you get the error far from the cause. Keep dependencies.php exhaustive and consider a boot-time smoke test that resolves your top-level services.

Extension points worth knowing: Hyperf\Di\Definition\ObjectDefinition, FactoryDefinition, and Reference let you express custom construction; Container::define() adds definitions at runtime (useful in packages' ConfigProvider — the idiomatic Hyperf way to ship bindings). Prefer ConfigProvider-declared dependencies over imperative define() calls scattered through bin/hyperf.php.

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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections