mrclay / props-dic
Props 是一个简单的依赖注入容器,允许通过自定义属性和方法名称来检索值
Requires
- php: >=8.1.0
- pimple/pimple: ~3.0
- psr/container: ^2.0
Requires (Dev)
- phpunit/phpunit: 10
README
大多数 依赖注入 容器都有获取操作,如 $di->get('foo')
或 $di['foo']
,这不会让你的 IDE 知道接收到的值的类型,也不会提供任何帮助来记住/输入键名。
使用 Props,你可以通过自定义属性读取 $di->foo
或方法调用 $di->new_foo()
来访问值。这允许你子类化容器并提供 @property
和/或 @method
PHPDoc 声明,为你的 IDE 和静态分析工具提供有价值的运行时类型信息。
一个例子将有所帮助
/** * @property-read Foo $foo * @method Foo new_foo() */ class MyContainer extends \Props\Container { public function __construct() { $this->foo = function (MyContainer $c) { return new Foo(); }; } } $c = new MyContainer(); $foo1 = $c->foo; // your IDE knows this is a Foo instance $foo2 = $c->new_foo(); // A fresh Foo instance $foo3 = $c->foo; // same as $foo1
这是一个更复杂的例子
/** * @property-read string $style * @property-read Dough $dough * @property-read Cheese $cheese * @property-read Pizza $pizza * @method Slice new_slice() */ class PizzaServices extends \Props\Container { public function __construct() { $this->style = 'deluxe'; $this->dough = function (PizzaServices $c) { return new Dough(); }; $this->setFactory('cheese', 'CheeseFactory::getCheese'); $this->pizza = function (PizzaServices $c) { $pizza = new Pizza($c->style, $c->cheese); $pizza->setDough($c->dough); return $pizza; }; $this->slice = function (PizzaServices $c) { return $c->pizza->getSlice(); }; } } $c = new PizzaServices; $c->pizza; // This first resolves and caches the cheese and dough. $c->pizza; // The same pizza instance as above (no factories called).
由于 "slice" 设置了工厂函数,我们可以调用 new_slice()
从它那里获取新的实例
$c->new_slice(); // a new Slice instance $c->new_slice(); // a new Slice instance
你的 IDE 将容器视为一个具有类型属性的普通旧类,允许它提供可用的属性建议、自动完成名称以及自动完成返回的对象。它在提供静态分析和自动化重构时提供了更多功能。
兼容性
Props\Container
实现 ContainerInterface
。
概述
你可以通过直接设置来指定依赖关系
$c->aaa = new AAA();
你可以通过设置一个 Closure
或使用 setFactory()
方法来指定工厂。这些在功能上是等效的
$c->bbb = function ($c) { return BBB::factory($c); }; $c->setFactory('bbb', 'BBB::factory');
已解析的依赖关系被缓存,返回相同的实例
$c->bbb === $c->bbb; // true
使用工厂
如果你不希望使用缓存值,请使用 new_PROPERTYNAME()
总是获取一个新的实例
$c->new_bbb() === $c->new_bbb(); // false
常规值集不存储工厂,因此在使用 new_PROPERTYNAME()
之前,你可能需要检查 hasFactory()
// store a value $c->ccc = new CCC(); $c->hasFactory('ccc'); // false // store a factory $c->ccc = function () { return new CCC(); }; $c->hasFactory('ccc'); // true
你也可以获取到设置工厂的访问权限
$callable = $c->getFactory('ccc');
扩展工厂
使用 extend
在返回值之前进行过滤
$c->foo = function ($c) { return new Foo($c->bar); }; $c->extend('foo', function ($value, Container $c) { return array($value, $c->bing); }); $c->foo; // [Foo, "bing"] $c->new_foo(); // re-call original foo factory and re-extend output (`bar` and `bing` will be re-read)
带有属性访问的 Pimple
如果你习惯了 Pimple API,尝试 Props\Pimple
,它只添加了属性访问。这样你就可以添加 @property
声明并得到相同的类型优势。
你可以看到一个 例子,它与 Pimple 文档相似。
要求
- PHP 8.1
许可 (MIT)
查看 LICENSE。