godruoyi/easy-container
godruoyi/easy-container is a lightweight PHP/Laravel service container that simplifies dependency injection, binding, and singleton management. Its small API makes registering and resolving services fast, clean, and easy to integrate into Laravel applications.
godruoyi/easy-container is a thin static facade over illuminate/container — it lets you use Laravel's DI container in plain PHP scripts, CLI tools, and small non-Laravel services without pulling in the framework.
composer require godruoyi/easy-container
Version 3.0.0 requires PHP 8.1+. The only functional change in this release is PHP 8.1 support (PR #5) plus README updates — but the major version bump means the constraint floor moved. If you are still on PHP 7.4 or 8.0, pin ^2.0; if you are already on 8.1+, upgrading is a constraint change and nothing else.
First place to look: the README (godruoyi/easy-container on GitHub). It is short and is effectively the whole API surface — there is no config file, no service provider, no publishable assets.
Minimal first use case — register your dependencies once at bootstrap and resolve them by type:
use Godruoyi\Container\Container;
Container::singleton(PDO::class, fn () => new PDO(getenv('DSN')));
Container::bind(MailerInterface::class, SmtpMailer::class);
// Autowired — constructor deps resolved by reflection
$service = Container::make(ReportService::class);
That is the entire value proposition: make() with reflection-based autowiring and interface binding, callable from anywhere via static methods.
Bootstrap file as the composition root. Put all bind/singleton calls in a single bootstrap/container.php required from your entry points (public/index.php, bin/console, test bootstrap). Treat it as your AppServiceProvider — keep it declarative and free of side effects.
Interface-first bindings, concrete resolution. Bind contracts to implementations at bootstrap, then type-hint the interface in constructors and let make() wire the graph:
Container::bind(CacheInterface::class, RedisCache::class);
Container::singleton(LoggerInterface::class, fn ($c) => new FileLogger($c->make(Config::class)));
Singletons for anything stateful or expensive. DB connections, config objects, HTTP clients, and loggers should be singleton(). Everything else should be bind() so you get a fresh instance per resolve.
Constructor injection everywhere, make() only at the edges. Resolve the top-level object from your entry point and let the container handle the rest through constructor type-hints. Calling Container::make() deep inside business logic is a service-locator smell and makes unit testing painful.
Invoke callables through the container. For command handlers or route callbacks in a micro-app, Container::call($handler) injects dependencies into method parameters — this is the same mechanism Laravel's route dispatcher uses.
Sharing with third-party libraries. If a library you use also resolves from illuminate/container, it will pick up the same instance via Container::getInstance(). Conversely, in tests or in an app that already has a container, use Container::setInstance($existing) to align them rather than maintaining two graphs.
Do not use this inside a Laravel application. Inside Laravel you already have app(), resolve(), and the framework's container with its full binding set. Adding this package there only creates a second, divergent container that will not see framework bindings.
Container::setInstance(null) (or re-run your bootstrap) in tearDown().>=8.1 with older PHP dropped. Verify composer.json before upgrading a legacy project; otherwise stay on ^2.0.tagged() exists via the underlying container, but there is nothing framework-level; you collect tagged bindings yourself.BindingResolutionException with a vague message. If autowiring fails, check the constructor chain first — the reflection error rarely names the offending class directly.fn ($c) => ...) rather than eagerly constructing objects at bootstrap, or you will instantiate services your code path never needs.Container::bound(Foo::class) to confirm a binding exists and Container::getBindings() to dump what is registered. Wrapping make() in a try/catch and logging the class name is usually faster than reading the stack trace.extend() to decorate an already-registered binding, rebinding() callbacks to react when a binding is replaced (useful for hot-swapping in tests), and afterResolving() to attach behavior to any resolved instance.How can I help you explore Laravel packages today?