dc / ioc
简单的IoC容器
Requires (Dev)
- phpunit/phpunit: 4.0.*
This package is not auto-updated.
Last update: 2024-09-14 15:00:49 UTC
README
安装
$ composer install dc/ioc
或者将其添加到 composer.json
"require": {
"dc/ioc": "0.*"
}
$ composer install
注册
您可以使用容器注册对象、类和工厂函数。
注册一个类
$container = new \DC\IoC\Container(); $container ->register('\Car') // fully qualified namespace ->to('\IVehicle') ->withContainerLifetime(); // lives as long as the container
注册一个实例(实例注册不支持生命周期,它们始终与容器一样长)
$container ->register(new \Car()) ->to('\IVehicle');
注册一个工厂函数
$container ->register(function() { new \Car(); })->to('\IVehicle');
理解生命周期
有三种可能的生命周期注册:withPerResolveLifetime()、withContainerLifetime() 和 withSingletonLifetime()。当您将类名或工厂函数传递给 register() 时可以使用这些,但如果不传递对象实例,则不能使用。
withPerResolveLifetime()每次解析时都会创建一个新实例。withContainerLifetime()将从该容器解析相同的实例。withSingletonLifetime()将从所有容器解析相同的实例。
解析服务
您可以直接查询容器来解析服务。
$vehicle = $container->resolve('\IVehicle');
如果您为相同的接口或类名有多个注册,您可以使用 resolveAll()。
$vehicles = $container->resolveAll('\IVehicle');
构造函数注入
使用类型提示将依赖项注入到类中。
class Trailer { public __construct(\IVehicle $vehicle) { // attach your Trailer to you IVehicle, or something } } $container->resolve("Trailer"); // you don't even have to register Trailer
如果您不想使用类型提示,可以使用 PhpDoc 注释代替。这在您想获取某个数组的数组时特别有用,因为 PHP 的类型提示语法不支持这一点。
class Trailer { /** * @param $matchesVehicles array|\IVehicle[] */ public __construct(array $matchesVehicles) { } }
甚至更简单
class Trailer { /** * @param $matchesVehicles \IVehicle[] */ public __construct($matchesVehicles) { } }
属性注入
通过容器解析的所有对象将扫描其非静态属性以查找可能的依赖项。要标记属性为可注入,它需要一个 @var 和一个 @inject PhpDoc 声明。
class Car { /** * @inject * @var \Trailer */ private $trailer; }
对于尚未通过容器解析的对象(即您自己构建的对象),您可以使用 inject() 方法应用属性注入。
$car = new Car(); $container->inject($car);
工厂注入
当您向注册提供工厂函数时,您可以像在构造函数中一样注入其他服务。您可以选择依赖类型提示或 PhpDoc 注释(用于注入数组)。
$container->register(function(\IFoo $foo) { return new Bar($foo); })->to('\Bar');
$container->register( /** * @param $foos \IFoo[] */ function(array $foos) { return new Bar($foos); })->to('\Bar');
模块
如果您有一个需要注册大量服务的大项目,实现模块可能是最佳选择。
扩展 \DC\IoC\Modules\Module 并指定您的模块名称以及它所依赖的模块。
class MyModule extends \DC\IoC\Modules\Module { public __construct() { parent::__construct("package-name", ["dc/router"]); } public register(\DC\IoC\Container $container) { $container->register('\Foo')->to('\Bar'); } }
在(最好在)注册您的服务之前,首先注册所有模块
$container->registerModules([new MyModule(), new \DC\Router\Module()]);
容器将尝试以正确的顺序注册任何依赖。
性能
可以在本存储库的 perf/ 文件夹中找到一些粗略的性能测试。它们显示以下(数字来自在我机器上运行的虚拟机)
- 单个注册大约使用 600 字节内存,耗时 0.03 毫秒。 除非您正在注册数千个服务,否则速度和内存不应成为限制因素。对于每个页面视图少于一百个注册的典型设置,您应该期望它在大多数情况下只增加不到 25 毫秒。
- 解析是微不足道的。返回 10 个对象的
resolveAll-调用平均耗时 0.09 毫秒(解析 10 个对象)。 - 构造函数和函数注入使用反射完成,这通常被认为很慢。同样,解析单个接口需要 0.06 毫秒。
