wilaak/picodi

A stupidly simple PHP dependency injection container.

v0.1.0-alpha.1 2025-06-05 09:40 UTC

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.