nimayneb / yedi
足够的依赖注入器
Requires
- php: ^7.4
- php-ds/php-ds: ^1.2
- psr/container: ^1.0
Requires (Dev)
- captainhook/captainhook: ^5.3
- nimayneb/phpqg: 1.0.0
- pdepend/pdepend: ^2.7
- phpmd/phpmd: ^2.8
- phpmetrics/phpmetrics: ^2.6
- phpunit/phpunit: ^7.5
- squizlabs/php_codesniffer: ^3.5
This package is auto-updated.
Last update: 2024-09-08 11:51:31 UTC
README
这是一个小巧且易于使用的依赖注入(也称为DI)框架。
特性
- 流畅的接口
- 容器与PSR-11兼容...
- 使用数据结构映射(参见 https://php.ac.cn/manual/en/class.ds-map.php)
- 将类/接口或特性委托给另一个具体类(参见"别名容器的使用")
- 使用配置的构造函数参数实例化依赖项(参见"解析容器的使用")
- 不作为反模式使用单例行为(如果需要,每个类只能存在一次)
- DI Getter 特性
使用注入器
每次你想注入一个依赖类时,都可以使用DI。
首先,这并不是真的很繁琐
$di = new JayBeeR\YEDI\DependencyInjector;
$object = $di->get(My\Own\Class::class);
每个类都将通过纯DI方法内部构建
class MyOwnClass
{
protected My\Own\Interface $stuff;
public function __construct(My\Own\OtherClass $stuff)
{
$this->stuff = $stuff;
}
}
$di = new JayBeeR\YEDI\DependencyInjector;
$myClass = $di->get(MyOwnClass::class);
构造函数参数中给出的类类型 $stuff
将自动反射并在实例化请求的类之前进行DI委托。
你可以用任何形式使用这个类而不使用DI
$dependentClass = new My\Own\OtherClass;
$myClass = new MyOwnClass($dependentClass);
你可以在自己的类中使用getter特性(但要注意它)
class MyOwnClass
{
use JayBeeR\YEDI\DependencyInjectorGetter;
protected My\Own\Interface $stuff;
public function injectDependencies()
{
$this->stuff = $this->get(My\Own\OtherClass::class);
}
}
(!) YEDI类只能有特性构造函数。这是因为你不可以通过进一步实现轻松地在这个类中使用相同的DI。你必须向该类传递现有的DI。不愉快的是:额外的参数只会使构建类更困难。因此,我们只使用特性构造函数来传递DI。其他所有内容都通过名为"injectDependencies"的抽象方法注入。
你可以使用它,但...你只是不必要地依赖于DI。
别名容器的使用
别名容器应该用于映射将被覆盖的类。应该是(抽象)类、接口或特性。
$di = new JayBeeR\YEDI\DependencyInjector;
$di->delegate(ForeignClass::class) ->to(MyExtendedClass::class);
$di->delegate(ForeignInterface::class) ->to(MyClassWithThisInterface::class);
$di->delegate(ForeignTrait::class) ->to(MyClassWithThisTrait::class);
你可以这样使用它
$myExtendedClass = $di->get(ForeignClass::class);
$myClassWithThisInterface = $di->get(ForeignInterface::class);
$myClassWithThisTrait = $di->get(ForeignTrait::class);
从外部类,你现在可以控制内部依赖,而无需扩展此类。
然而,YEDI提供了更多的支持。继续阅读。
解析容器的使用
解析容器应该用于使用具体构造函数参数实例化依赖类。
class ForeignClass {
public function __construct(
string $name,
Foreign\HelperInterface $helper,
int $limit,
bool $hidden,
Foreign\Service $service
);
}
$di = new JayBeeR\YEDI\DependencyInjector;
$di->for(ForeignClass::class)
->setArgument('limit') ->to(123)
->setArgument('name') ->to('value')
->setArgument('helper') ->asInjection(My\Own\Helper::class)
->setArgument('hidden') ->to(false)
->setArgument('service') ->asSingleton(My\Own\Service::class)
;
$foreignClass = $di->get(ForeignClass::class);
这会与以下实现相同
$dependentHelper = new My\Own\Helper;
// should return singleton instance via Factory
$service = Foreign\Service::get();
$object = new ForeignClass(123, 'value', $dependentHelper, false, $service);
但为什么你应该使用这个呢?
让我们想象你有两个类,它们为接口提供了不同的实现。
然而,使用YEDI的别名支持,你不能将此接口委托给这两个类。
这就是情况
class MyClassA
{
public function __construct(ForeignInterface $interface);
}
class MyClassB
{
public function __construct(ForeignInterface $interface);
}
这就是解决方案
$di = new JayBeeR\YEDI\DependencyInjector;
$di->for(MyClassA::class)
->setArgument('interface')
->asInjection(MyClassInterfaceA::class)
;
$di->for(MyClassB::class)
->setArgument('interface')
->asInjection(MyClassInterfaceB::class)
;
你现在可以用简单的类名实例化
$di = new JayBeeR\YEDI\DependencyInjector;
// constructor argument with MyClassInterfaceA
$myClassA = $di->get(MyClassA::class);
// constructor argument with MyClassInterfaceB
$myClassB = $di->get(MyClassB::class);
单例类使用
有时你想要确保某些类不能被实例化多次。这就是Singleton设计模式的意义所在。它也被称为反模式,因为存在几个缺点。
你可以使用单例实例而不使用此模式
$di = new JayBeeR\YEDI\DependencyInjector;
// Global Singleton delegation
$di->delegate(Foreign\Class:class)->asSingleton(); // via ReflectionType
$di->delegate(Foreign\Class:class)->asSingleton(MyOwn\Class::class);
// Local Singleton delegation
$di->for(Foreign\Class:class)->setArgument('service')->asSingleton(); // via ReflectionType
$di->for(Foreign\Class:class)->setArgument('service')->asSingleton(MyOwn\Service::class);
(!) 使用单例时应小心,因为这些不是立即生成的,而只是在第一次通过DI请求时生成。这里的顺序可能取决于其他实例将在何时创建。
愿望清单
- 重构和重命名事物(清晰的接口)
- 所有异常的描述 <3
- 所有异常的测试
- 抛出更多的异常?
PDepend
- NOP - 包的数量
- NOC - 类的数量
- NOM - 方法的数量
- LOC – 代码行数
- CYCLO - 节点复杂度
- 函数和方法调用次数
- 平均派生类数
- 平均层次高度