A minimalistic, PSR-11 compliant dependency injection container with automatic constructor injection and zero configuration.
- 🚀 Zero Configuration: Automatic constructor injection without verbose setup
- 🔄 Circular Dependency Detection: Clear error messages when dependencies form a loop
- 📦 PSR-11 Compliant: Standard container interface for interoperability
- ⚡ Performance Optimized: Warm resolution builds straight to
new, plus warmup, a compiled cache that skips reflection, and one plan cache shared across sibling containers - 🧩 Fluent Registration: Register bindings after construction with
bind(),singleton()andlazy() - 🌱 Scopes: Child containers that inherit registration without copying it, for per-request lifetimes
- 🎁 Typed Resolution:
make()returns a typed instance;getOrFail()never returnsnull - 🧵 Tags: Group services under a tag and resolve them lazily, as a list or as a keyed map
- 🧭 Contextual Bindings:
when()scopes a dependency — or a scalar — to the classes that ask for it - 📄 Definitions as Data: Ship and override wiring as arrays, PHP, JSON or YAML files with
load()/loadFile() - 🪝 Resolution Hooks:
afterResolving()callbacks run once an id is built - 🔍 Introspection: Debug and inspect container state easily
- 🎯 Type Safe: Requires type hints for reliable dependency resolution
- 🏷️ PHP 8 Attributes: Declarative configuration with
#[Inject],#[Singleton],#[Factory]and#[Lazy]— on parameters, properties and setters, and subclassable under your own namespace - ✅ Build-time Validation:
validate()proves a set of classes resolves without resolving them, so broken wiring fails a deploy instead of a request - 🛠️ A CLI:
gacela-container compile|report|validate— no console framework,psr/containerstays the only runtime dependency - 🎀 Built to be Wrapped:
withSelfReference()hands a decorator's facade to service closures, so composing over thefinalcontainer costs one call
composer require gacela-project/containerRequires PHP >= 8.3.
use Gacela\Container\Container;
class Greeter {
public function __construct(private Clock $clock) {}
public function greet(): string {
return 'Hello World at ' . $this->clock->now();
}
}
class Clock {
public function now(): string {
return date('H:i:s');
}
}
// Zero configuration — dependencies are auto-wired from type hints
$container = new Container();
$greeter = $container->make(Greeter::class);
echo $greeter->greet();Need interfaces, singletons, attributes, or a compiled cache? See the docs below.
| Gacela | Pimple | Laravel | PHP-DI | Symfony | |
|---|---|---|---|---|---|
| PSR-11 | ✅ | wrapper | ✅ | ✅ | ✅ |
| Autowiring with zero config | ✅ | ❌ | ✅ | ✅ | needs config |
| Framework-independent | ✅ | ✅ | pulls illuminate/contracts |
✅ | ✅ |
| Lifetimes as attributes | #[Singleton] #[Factory] #[Lazy] |
❌ | ❌ | #[Inject] only |
#[Autoconfigure] |
| Property injection | ✅ #[Inject] |
❌ | ❌ | ✅ | via config |
| Lazy services | ✅ native lazy objects (PHP 8.4+), attribute or lazy(), no proxy class |
❌ | ❌ | ✅ via proxy library | ✅ |
| Compiled resolution | ✅ plans + generated factories | ❌ | ❌ | ✅ | ✅ |
| Reflection shared across sibling containers | ✅ PlanCache, in-process |
❌ | ❌ | via APCu cache | n/a — dumped once |
| Child/scope containers | ✅ inherits without copying | ❌ | ❌ | ❌ | ❌ |
| Contextual bindings | ✅ | ❌ | ✅ | definitions | ✅ |
| Tags | ✅ list or keyed map | ❌ | ✅ | ❌ | ✅ |
| Resolution hooks | ✅ afterResolving() |
❌ | ✅ | ❌ | ❌ |
| Invoke any callable | ✅ resolve() |
❌ | ✅ call() |
✅ call() |
❌ |
| Circular dependencies | ✅ named exception + path | ❌ | ✅ | ✅ | ✅ at compile time |
| Introspection | ✅ stats(), dependency tree, compileReport(), typo hints |
❌ | ❌ | limited | ✅ via console |
| Array access | ✅ | ✅ | ✅ | ❌ | ❌ |
| Definitions as data | ✅ arrays, PHP + JSON + YAML files | ❌ | ❌ | ✅ | ✅ |
| YAML definition files | ✅ optional, via symfony/yaml — never a hard dependency |
❌ | ❌ | ✅ | ✅ |
| XML definition files | ❌ by design — parse it and load() the array |
❌ | ❌ | ❌ | ✅ |
| Build-time validation | ✅ validate(), gacela-container validate |
❌ | ❌ | ❌ | ✅ via compiler passes |
| Compiler passes / extensions | ❌ by design — packages expose definitions instead | ❌ | ❌ | ❌ | ✅ |
Use this if you want Pimple's footprint with real autowiring, or Laravel's container API without Laravel — plus lazy services, per-request scopes, and a compiled cache that skips reflection entirely.
Look elsewhere if you need XML definitions or compiler-pass style extension
points. Both are deliberate boundaries rather than a backlog — XML has no
canonical mapping to a definition array short of inventing a schema
(#139), and passes
operate on a definition set an autowiring container mostly does not have
(#140) — the two
things passes are actually reached for are covered instead: validate() gives
the build-time feedback, and a package registers services by exposing
definitions for load(). Each issue records the reasoning and what would change
it. YAML is supported, as a
suggest — install symfony/yaml and loadFile() reads it; the runtime
requirement is still psr/container alone.
| Guide | What's inside |
|---|---|
| Getting Started | Installation, basic usage, how resolution works |
| Bindings & Registration | Constructor bindings, bind()/singleton(), contextual bindings, aliasing |
| Definitions as Data | load()/loadFile(): wiring from arrays, PHP, JSON and YAML files |
| Resolving Services | get(), make(), getOrFail(), resolve(), transient vs. shared |
| PHP 8 Attributes | #[Inject], #[Singleton], #[Factory], #[Lazy] |
| Managing Services | Factories, extending, protecting closures, introspection |
| Scopes | Child containers: inherited registration, per-request lifetimes |
| Performance & Compilation | warmUp(), compiled cache, generated factories, validate(), the CLI |
| Cookbook | Recipes: testing, config, plugins, decorating, debugging |
| Error Handling | Every exception, what causes it, how to fix it |
| Best Practices | Recommended patterns |
| API Reference | Full method, static, and attribute reference |
| Backward Compatibility | What semver covers here, and what it does not |
| Upgrade Guide | Migrating to 2.0, and 0.10.0 to 1.0.0 |
See how it's used in the Gacela Framework.
composer test # Run tests
composer quality # Run static analysis
composer test-coverage # Generate coverage reportMIT License. See LICENSE file for details.