denosyscore / container
PSR-11 compliant dependency injection container with autowiring, contextual bindings, and service decorators for PHP 8.2+
Requires
- php: ^8.2
- denosyscore/contracts: ^0.2
- denosyscore/events: ^0.2
- psr/container: ^2.0
Requires (Dev)
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- v1.0.0
- dev-main / 0.22.x-dev
- v0.22.0
- v0.21.0
- v0.20.0
- v0.19.0
- v0.18.0
- v0.17.0
- v0.16.0
- v0.15.0
- v0.14.0
- v0.13.0
- v0.12.0
- v0.11.1
- v0.11.0
- v0.10.0
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.0
- dev-docs/readme-rewrite
- dev-style/mi3-mi6-docblock-psr12
- dev-feat/mi4-real-validator
- dev-fix/m4-mi1-profiler-and-typehint
- dev-chore/remove-dead-code
- dev-fix/m5-multi-resolution-double-build
- dev-fix/m3-scoped-binding-snapshot
- dev-fix/c3-service-spy-proxy
- dev-fix/mi5-alias-validation
- dev-fix/m1-deferred-provider-alias-order
- dev-fix/c2-singleton-decorator-cache-order
- dev-fix/c1-contextual-binding-stack
- dev-refactor/final-quality
- dev-refactor/psr12-import-groups
- dev-docs/readme
- dev-feat/container-validator
- dev-feat/container-validator-v2
- dev-refactor/orphaned-files
- dev-feat/ci
- dev-fix/multi-resolution
- dev-fix/scoped-bindings
- dev-fix/scoped-test-improvement
- dev-fix/scoped-bindings-v2
- dev-fix/failing-tests
- dev-feat/production-ready
This package is auto-updated.
Last update: 2026-11-13 14:04:47 UTC
README
Read-only split. This package is developed in denosyscore/framework under
packages/container. Open issues and pull requests there.
A small PSR-11 container: explicit bindings, shared instances, aliases and
constructor autowiring. Constructor parameters can ask for values the
container cannot infer from a type, using attributes such as
#[Config('app.key')].
Installation
composer require denosyscore/container
Quick Start
<?php require __DIR__ . '/vendor/autoload.php'; use Denosys\Container\Container; interface Clock { public function now(): DateTimeImmutable; } final class SystemClock implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable(); } } final class Greeter { // Constructor dependencies are resolved automatically. public function __construct(private Clock $clock) {} public function greet(string $name): string { return ($this->clock->now()->format('H') < 12 ? 'Good morning' : 'Hello') . ", {$name}"; } } $container = new Container(); $container->singleton(Clock::class, SystemClock::class); echo $container->get(Greeter::class)->greet('Ada'), "\n"; var_dump($container->get(Clock::class) === $container->get(Clock::class)); // bool(true)
Bindings
$container->bind(Clock::class, SystemClock::class); // a new instance each time $container->singleton(Mailer::class, SmtpMailer::class); // built once, then reused $container->singleton(Report::class, fn (Container $c) => new Report($c->get(Clock::class))); $container->instance(Settings::class, $settings); // an existing object $container->alias('mailer', Mailer::class); $container->extend(Mailer::class, fn (Mailer $mailer, Container $c) => new LoggingMailer($mailer));
A class with no binding is autowired: constructor parameters with class or
interface types are resolved from the container; nullable parameters receive
null and other parameters their default when nothing can supply them.
Parameter attributes
use Denosys\Container\Attributes\Config; use Denosys\Container\Attributes\Inject; final readonly class SignsLinks { public function __construct( #[Config('app.key')] private string $key, // read through the bound ConfigReader #[Config('links.ttl')] private int $ttl = 3600, // default when the setting is absent #[Inject('cache.redis')] private Cache $cache, // a specific binding, not the type's default ) {} }
Any attribute that implements Denosys\Container\ParameterResolver works the
same way, so applications can add their own.
Errors
get() throws NotFoundException (PSR-11 NotFoundExceptionInterface) for
an identifier it cannot provide, so has() and get() agree. A failure while
building an entry it can provide throws ContainerResolutionException, which
names the entry, lists the resolution stack and keeps the cause. Circular
dependencies are reported the same way.
License
MIT