modethirteen / opencontainer
PHP 依赖注入容器,请负责任地使用
Requires
- php: ~7.4.12
- ocramius/proxy-manager: ~2.10.0
- psr/container: ~1.0.0
Requires (Dev)
- phpstan/phpstan: ~0.12.57
- phpunit/phpunit: ~9.4.3
README
PHP 依赖注入容器,请负责任地使用。
关于
OpenContainer 是为了在具有完整功能的 PHP 开发环境中利用严格的类型检查而创建的,例如 JetBrains PHPStorm 或 PHP 7+ 的原生严格类型检查,当从集中式容器管理依赖项时。此外,它包含了一些关于反射和代理的实验,以避免在容器依赖链中引入循环依赖时出现的问题。
除了将依赖项公开为经过类型检查的类属性外,OpenContainer 还与 PSR-11 容器接口 兼容,以便与多个 PHP 框架进行互操作。
需求
- PHP 7.4 (主要,2.x)
安装
使用 Composer。将 OpenContainer 添加到项目的两种方法。
从 composer CLI
./composer.phar require modethirteen/opencontainer
或将 modethirteen/opencontainer 添加到项目的 composer.json 文件中
{ "require": { "modethirteen/opencontainer": "dev-main" } }
dev-main
是主要开发分支。如果您在生产环境中使用 OpenContainer,建议您使用稳定版本。
假设您已设置 Composer 的自动加载器,OpenContainer 可以在 modethirteen\OpenContainer\
命名空间中找到。
将 OpenContainer 添加到您的应用程序
只需实例化 OpenContainer 即可。
$container = new OpenContainer();
可注入类
可注入类在构建时通过注入容器进行实例化。在此示例中,Foo、Bar 和 Baz 都是容器中注册的类型。如果容器中注册的类型需要 Baz 的方法 doSomething(),Baz 必须首先从容器中获取它的依赖项 Foo 和 Bar(以及它们的依赖项,创建依赖树)。
class Baz { private Foo $foo; private Bar $bar; public function __construct(IContainer $container) { $this->foo = $container->Foo; $this->bar = $container->Bar; } public function doSomething() : string { return $this->foo->myMethod(); } }
注册类型
注册类型需要符号来标识从容器获取其实例化实例时的类型,以及构建的完全限定类名。
/** * setup the type as a virtual property so that IDE's that support type checking can take advantage * * @property Foo $Foo */ class MyContainer extends OpenContainer { } $container = new MyContainer(); $container->registerType('Foo', Foo::class); // type checks will infer this object to be an instance of Foo $instance = $container->Foo;
注册实例
注册实例需要符号来标识从容器获取实例时的实例,以及已创建的实例本身。注册实例在类型的构造函数无法满足可注入类的要求时很有用。
/** * setup the type as a virtual property so that IDE's that support type checking can take advantage * * @property Bar $Bar */ class MyContainer extends OpenContainer { } $container = new MyContainer(); $container->registerInstance('Bar', new Bar($dependency, $outside, $of, $container)); // type checks will infer this object to be an instance of Bar $instance = $container->Bar;
注册构建器
注册构建器需要符号来标识从容器获取实例时的实例,以及一个闭包函数,在第一次获取时执行。注册构建器在创建实例之前必须执行一些专用步骤时很有用。
/** * setup the type as a virtual property so that IDE's that support type checking can take advantage * * @property Qux $Qux */ class MyContainer extends OpenContainer { } $container = new MyContainer(); $container->registerBuilder('Qux', function(MyContainer $container) : Qux { // builder functions only have one argument, access to the container itself return new Qux($container, $some, $other, $dependency); }); // type checks will infer this object to be an instance of Qux $instance = $container->Qux;
延迟容器
延迟容器试图使用反射和类代理来避免循环依赖。延迟容器返回代理,直到在代理上访问方法或属性时才实例化。此行为很有用,因为没有它,树中的每个依赖项在根依赖项首次实例化时都会实例化(无论这些下游依赖项最终是否会被使用)。如果不将依赖项实例化延迟到实际需要时,任何循环依赖都会返回空值、无限嵌套函数循环,或者在无法解决时引发 未定义属性 警告。
$container = (new OpenContainer)->toDeferredContainer(); // all methods on a deferred container are identical to a non-deferred container $container->registerType('Plugh', Plugh::class); $container->registerInstance('Plugh', new Plugh()); // closure function style builders require a return type, otherwise an OpenContainerCannotBuildDeferredInstanceException will be thrown $container->registerBuilder('Plugh', function(IContainer $container) : Plugh { ... }); $container->Plugh;