league/container
league/container is a lightweight PSR-11 dependency injection container for PHP. Define entries, factories, and autowiring-friendly services to manage application dependencies cleanly, with modern PHP support and solid tooling for testing and analysis.
league/container with minimal changes, as both implement the same interface. This is particularly useful for:
league/container is lightweight (~10KB) and optimized for speed.#[Inject], #[Resolve]), and service providers, which align with Laravel’s DI patterns.BeforeResolveEvent), enabling custom logic without subclassing Laravel’s container.league/container implement PSR-11, swapping them requires no code changes in most cases. Existing bindings (e.g., app()->bind()) will work identically.register() and boot() methods) are compatible with league/container’s ServiceProviderInterface, though some Laravel-specific features (e.g., app()->singleton()) may need manual adjustments.app()->when(X::class)->needs(Y::class)->give(Z::class)) is not natively supported in league/container. A custom event listener or delegate container would be needed to replicate this behavior.Route::get()) rely on the container’s resolution logic. Since league/container uses the same PSR-11 interface, facades will continue to work, but custom resolution logic (e.g., afterResolve()) may require adjustments.| Risk Area | Assessment | Mitigation |
|---|---|---|
| Context Binding | Laravel’s context binding is not directly supported. Custom logic would be needed to replicate this functionality. | Use Container::afterResolve() or event listeners to intercept and modify resolutions dynamically. |
| Service Provider Differences | Laravel’s AppServiceProvider and BootServiceProvider may need adjustments for league/container’s stricter typing or missing methods (e.g., provides() is required in v5+). |
Abstract service provider logic into a base class or use traits to ensure compatibility. |
| Performance Overhead | While league/container is lightweight, event listeners or custom resolution logic could introduce overhead. |
Profile performance and disable unused events (e.g., OnDefineEvent if not needed). |
| Attribute Resolution | Laravel’s autowiring (via #[Inject]) is similar but not identical to league/container’s attribute resolution. Some edge cases (e.g., union types) may behave differently. |
Test thoroughly with complex dependency graphs and adjust autowiring configurations if needed. |
| Migration Complexity | Swapping containers in a large codebase may require testing all resolved dependencies. | Use feature flags or environment-based container switching to test incrementally. |
app()->makeWith())?
league/container.afterResolve() or attribute-based resolution?
league/container’s implementation meets the same requirements.league/container requires PHP 8.3+, so ensure compatibility with the target Laravel version (e.g., Laravel 11+).league/container to justify the migration.league/container is a drop-in replacement for Laravel’s container, as both implement PSR-11. This means:
Route, Auth) will continue to work without changes.AppServiceProvider, third-party packages) will work if they adhere to PSR-11.app()->bind(), app()->singleton()) are functionally identical.#[Inject], #[Resolve]).BeforeResolveEvent).afterResolve()).forTag('queue.worker')).| Step | Action | Tools/Notes |
|---|---|---|
| 1. Assessment | Audit dependencies for Laravel-specific container usage (e.g., app()->makeWith(), context binding). |
Use phpstan or psalm to detect non-PSR-11 container calls. |
| 2. Dependency Update | Update composer.json to replace illuminate/container with league/container. |
json { "require": { "league/container": "^5.2" } } |
| 3. Service Provider Adjustments | Refactor service providers to use PSR-11 methods (e.g., get() instead of make()). Ensure provides() is implemented if using league/container v5+. |
Laravel’s register() method can remain unchanged, but boot() may need adjustments if using container-specific logic. |
| 4. Context Binding Workaround | Implement a custom event listener or delegate container to replicate Laravel’s context binding. | Example: Use Container::listen() to intercept BeforeResolveEvent and apply conditional logic. |
| 5. Testing | Test all dependency resolutions, facades, and service providers. Pay special attention to: |
#[Inject] works as expected).phpunit with RefreshDatabase and WithFaker traits to test edge cases. |
| 6. Performance Benchmarking | Compare memory usage and resolution speed between Laravel’s container and league/container. | Use blackfire.io or xdebug to profile critical paths. |
| 7. Rollback Plan | Maintain a feature flag to switch between containers dynamically (e.g., via environment variable). | Example: php if (app()->bound('config')) { return app('config'); } with a fallback to the original container. || Feature | Laravel Container | league/container | Compatibility Notes |
|---|---|---|---|
| PSR-11 Compliance | ✅ Yes | ✅ Yes | Fully interchangeable. |
| Service Providers | ✅ Yes | ✅ Yes | Laravel’s register() and boot() work, but provides() may be required in v5+. |
| Context Binding | ✅ Yes | ❌ No | Requires custom event listener or delegate container |
How can I help you explore Laravel packages today?