uma / dic
一个极简的PSR-11容器
v4.0.0
2024-05-25 09:58 UTC
Requires
- php: ~8.2.0 || ~8.3.0
- psr/container: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.57
- phpmetrics/phpmetrics: ^3.0-rc
- phpunit/phpunit: ^11.1
- scrutinizer/ocular: ^1.9
Provides
README
一个专注于可读性和可理解的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