wilaak / picodi
A stupidly simple PHP dependency injection container.
Requires
- psr/container: ^2.0
This package is auto-updated.
Last update: 2025-06-05 13:19:39 UTC
README
A stupidly simple PHP dependency injection container.
Installation
Install PicoDI using Composer:
composer require wilaak/picodi
Requires PHP 8.3 or above
Table of Contents
Usage examples
Below are some examples to help you get started with the container.
Basic Example
interface LoggerInterface {} class LoggerService implements LoggerInterface {} $config = [ LoggerInterface::class => LoggerService::class, ]; $container = new Wilaak\PicoDI\ServiceContainer($config); $logger = $container->get(LoggerInterface::class);
Autowiring
PicoDI supports autowiring, allowing you to type-hint constructor parameters without explicit configuration:
class Bar { public function hello() { echo 'Hello, World!'; } } class Foo { public function __construct( private Bar $bar ) {} } $container = new Wilaak\PicoDI\ServiceContainer([]); $foo = $container->get(Foo::class); $foo->bar->hello();
Advanced Example
class DatabaseService { public function __construct( string $dsn, ?string $username = null, ?string $password = null, array $options = [], private ?LoggerInterface $logger = null ) {} } $config = [ LoggerInterface::class => LoggerService::class, LoggerService::class => function() { return new LoggerService( logPath: config('log_path'), logLevel: config('log_level'), ); }, DatabaseService::class => [ 'dsn' => fn() => 'mysql:host=localhost;dbname=mydb;charset=utf8mb4', 'username' => fn() => 'dbuser', 'password' => fn() => 'secret', 'options' => fn() => [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ], 'logger' => LoggerService::class, ], ]; $container = new Wilaak\PicoDI\ServiceContainer($config); $databaseService = $container->get(DatabaseService::class);
Configuration Options
The configuration array specifies how the container resolves dependencies. Each key serves as an identifier, usually the fully qualified class or interface name, while the value defines the resolution strategy. The following value types are supported:
1. String or ::class
Syntax (Alias)
Defines an alias for the class or interface specified in the key.
LoggerInterface::class => LoggerService::class,
This maps the LoggerInterface
to the LoggerService
implementation. Using ::class
is essentially the same as providing a string, but we prefer the ::class
syntax because it is more readable and plays better with autocompletion.
Here’s the same example without using the ::class
syntax:
'LoggerInterface' => 'LoggerService',
This achieves the same result, but using strings directly can be less readable.
2. Callable (Factory Function)
Use a callable (e.g Closure, Arrow Function) to explicitly return the desired value.
LoggerService::class => function() { return new LoggerService( path: '/var/log/log.txt', level: 'debug' ); },
3. Array (Constructor Injection)
Allows you to define constructor arguments for a class using an associative array. Each key corresponds to the name of a constructor parameter, while the value specifies how it should be resolved. You can also use positional arguments by omitting the keys.
- Use a string or
::class
syntax to alias another implementation that will be resolved from the container. - Use a callable (e.g Closure, Arrow Function) to explicitly return the desired value.
DatabaseService::class => [ 'dsn' => fn() => 'mysql:host=localhost;dbname=mydb;charset=utf8mb4', 'username' => fn() => 'dbuser', 'password' => fn() => 'secret', 'options' => fn() => [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ], 'logger' => LoggerService::class, ],
Learn
Attribution
Thanks to Evan Hildreth and his article: A Stupidly Simple PHP Dependency Injection Container for inspiring this project.