2.1.0 2024-03-24 14:52 UTC

This package is auto-updated.

Last update: 2024-08-24 15:43:35 UTC


README

Build Status codecov Type Coverage

使用单一方式定义服务的最小化依赖注入容器。

此外,没有缓存,因此没有缓存失效问题。

安装

composer require innmind/di

使用

use Innmind\DI\{
    Builder,
    Container,
};

$container = Builder::new()
    ->add('connection', fn(Container $get) => new ConnectionPool( // imaginary class
        $get('connection_a'),
        $get('connection_b'),
    ))
    ->add('connection_a', fn() => new \PDO('mysql://localhost'))
    ->add('connection_B', fn() => new \PDO('mysql://docker'))
    ->build();

$connection = $container('connection');
$connection instanceof ConnectionPool; // true

add 方法接受任何返回 objectcallable。这允许您使用匿名函数以提高易用性(但会有内存影响)或使用形式为 [Service::class, 'factoryMethod'] 的可调用对象,这样只有在服务加载时才加载类文件。

使用枚举代替字符串来引用服务

当通过 Builder::add() 添加服务时,使用 string 命名服务很简单,但静态分析工具无法确定返回服务的类型。这会导致需要抑制的 混合参数 错误。

相反,您可以使用枚举如下

use Innmind\DI\Service;

/**
 * @template S
 * @implements Service<S>
 */
enum Services implements Service
{
    case connection;
    case connectionA;
    case connectionB;

    /**
     * @return self<ConnectionPool>
     */
    public static function connection(): self
    {
        /** @var self<ConnectionPool> */
        return self::connection;
    }

    /**
     * @internal
     *
     * @return self<\PDO>
     */
    public static function connectionA(): self
    {
        /** @var self<\PDO> */
        return self::connectionA;
    }

    /**
     * @internal
     *
     * @return self<\PDO>
     */
    public static function connectionB(): self
    {
        /** @var self<\PDO> */
        return self::connectionB;
    }
}

并且可以这样使用它

use Innmind\DI\{
    Builder,
    Container,
};

$container = Builder::new()
    ->add(Services::connection, fn(Container $get) => new ConnectionPool( // imaginary class
        $get(Services::connectionA),
        $get(Services::connectionB),
    ))
    ->add(Services::connectionA, fn() => new \PDO('mysql://localhost'))
    ->add(Services::connectionB, fn() => new \PDO('mysql://docker'))
    ->build();

$connection = $container(Services::connection);
$connection instanceof ConnectionPool; // true

技巧

通过使用枚举,您可以轻松地在一个地方引用所有定义的服务。如果您分发您的包,用户可以查看枚举以了解他们可以使用哪些服务(因为您可以声明 @internal 服务)。

此外,服务的名称不再有拼写错误,并且服务会自动命名空间(包之间不可能发生冲突)。

注意

在枚举上使用命名构造函数来指定返回的类。Phantom 不允许在 case 中直接指定模板值。