uma/dic

一个极简的PSR-11容器

v4.0.0 2024-05-25 09:58 UTC

This package is auto-updated.

Last update: 2024-08-25 10:27:56 UTC


README

CI Code Coverage

一个专注于可读性和可理解的PSR-11容器。

安装

$ composer require uma/dic:^4.0

设计目标

简洁性

依赖注入容器是一个相对简单的概念,其实现也应该简单。

PSR-11兼容性

它必须实现PSR-11规范,并且可以在期望PSR-11容器的地方使用。

设置器

它必须有一种标准的方式向容器添加依赖关系以及检索它们。使用依赖注入容器涉及这两个操作,而不仅仅是获取它们(我指的是PSR-11)。

为此,`Container`类有一个`set`方法,并在其构造函数中接受一个可选的`string => mixed`类型的数组,这相当于调用`set($id, $entry)`,其中每个键值对都调用一次。

此外,定义必须是可覆盖的,因为在测试环境中,定义覆盖是一种常见的方法。

$container = new UMA\DIC\Container([
  'host' => 'localhost',
  'port' => 8080
]);

$container->set('foo', 'bar');
$container->set('foo', 'baz');
var_dump($container->get('foo'));
// 'baz'

延迟加载

必须可以注册延迟服务。这些服务直到第一次实际检索时才实例化。

该库使用匿名函数实现延迟服务。每当容器被要求提供一个实际上是匿名函数的服务时,该函数就会执行(传递容器本身作为第一个参数),并将结果存储在匿名函数曾经存在的地方。

此外,容器有一个`resolved`方法,它返回给定服务是否是匿名函数。这在需要断言测试代码中是否实际调用了给定服务时非常有用。

$container = new UMA\DIC\Container();
$container->set('dsn', '...');

// A database connection won't be made until/unless
// the 'db' service is fetched from the container
$container->set('db', static function(Psr\Container\ContainerInterface $c): \PDO {
  return new \PDO($c->get('dsn'));
});

var_dump($container->resolved('db'));
// false

$pdo = $container->get('db');

var_dump($container->resolved('db'));
// true

提供者

当项目涉及大量服务时,这些服务可以组织在提供者类中。

这些类实现`UMA\DIC\ServiceProvider`,并在其`provide`方法中接收容器的一个实例。然后期望它们在其中注册相关服务的集合。这个概念是从Pimple借用的。

$container = new UMA\DIC\Container();
$container->register(new Project\DIC\Repositories());
$container->register(new Project\DIC\Controllers());
$container->register(new Project\DIC\Routes());
$container->register(new Project\DIC\DebugRoutes());

服务工厂

在少数特殊情况下,每次从容器请求服务时,可能希望创建服务的新实例。

像延迟加载一样,服务工厂使用匿名函数实现。然而,它们是通过`factory`方法而不是`set`方法注册的。

$container = new UMA\DIC\Container();

// Normal lazy loaded service. Will always return the
// same object instance after running the Closure once.
$container->set('foo', static function(): \stdClass {
  return new \stdClass();
});

// Factory service. The second argument must be a Closure.
// The closure will run every time the service is requested.
$container->factory('bar', static function(): \stdClass {
  return new \stdClass();
});

// foo is always the same object instance.
var_dump($container->get('foo') === $container->get('foo'));
// true

// bar is a different object instance each time it's requested.
var_dump($container->get('bar') === $container->get('bar'));
// false