psx / dependency
简单快速的DI容器
v2.0.2
2022-01-09 01:08 UTC
Requires
- php: >=8.0
- psr/cache: ^1.0|^2.0|^3.0
- psr/container: ^1.1|^2.0
Requires (Dev)
- phpunit/phpunit: ^8.0
- symfony/cache: ^5.0
- vimeo/psalm: ^4.0
Provides
README
关于
一个简单快速的PSR-11兼容DI容器,具有自动绑定、标记和注入服务的功能。服务不是通过YAML或配置文件定义,而是在类中通过添加例如 getMyService
方法简单地定义。
使用方法
容器
可以扩展 Container
类。所有 getXXX
方法都是服务定义,可以通过 get
方法访问。
<?php use PSX\Dependency\Attribute\Tag; use PSX\Dependency\Container; use PSX\Dependency\Tests\Playground\FooService; use PSX\Dependency\Tests\Playground\BarService; class MyContainer extends Container { public function getFooService(): FooService { return new FooService(); } #[Tag('my_tag')] public function getBarService(): BarService { return new BarService($this->get('foo_service')); } }
自动绑定
以下示例展示了如何使用自动绑定功能
<?php use PSX\Dependency\Inspector\ContainerInspector; use PSX\Dependency\TypeResolver; use PSX\Dependency\AutowireResolver; use PSX\Dependency\Tests\Playground\MyContainer; use PSX\Dependency\Tests\Playground\AutowireService; $container = new MyContainer(); $inspector = new ContainerInspector($container); $typeResolver = new TypeResolver($container, $inspector); $autowireResolver = new AutowireResolver($typeResolver); $service = $autowireResolver->getObject(AutowireService::class);
自动绑定解析器检查 AutowireService
类构造函数的所有参数,并尝试根据容器中方法定义的返回类型解决每种类型。请查看测试用例以查看完整示例。
还可以提供一个工厂解析器,允许解决例如仓库类
<?php use Psr\Container\ContainerInterface; use PSX\Dependency\TypeResolver; use PSX\Dependency\AutowireResolver; use PSX\Dependency\Tests\Playground\RepositoryInterface; $typeResolver = new TypeResolver(...); $autowireResolver = new AutowireResolver($typeResolver); $typeResolver->addFactoryResolver(RepositoryInterface::class, function (string $class, ContainerInterface $container): RepositoryInterface { return $container->get('table_manager')->getRepository($class); }); // this now allows to use the MyRepository class as a type-hint at a service and // the autowire resolver injects the fitting service through the defined resolver $repository = $autowireResolver->getObject(MyService::class);
标记
以下示例展示了如何获取被特定标记注解的服务
<?php use PSX\Dependency\Inspector\ContainerInspector; use PSX\Dependency\TagResolver; use PSX\Dependency\Tests\Playground\MyContainer; $container = new MyContainer(); $inspector = new ContainerInspector($container); $tagResolver = new TagResolver($container, $inspector); $services = $tagResolver->getServicesByTag('my_tag');
要标记服务,需要在服务定义方法中添加 #Tag
属性。然后可以使用标记解析器接收所有添加了特定标记的服务。
编译器
如果已创建了一个大型容器,可以将此容器编译成优化的类,从而提高性能。
use PSX\Dependency\Compiler\PhpCompiler; use PSX\Dependency\Tests\Playground\MyContainer; $compiler = new PhpCompiler('Container', __NAMESPACE__); $container = new MyContainer(); // contains the compiled DI container $code = $compiler->compile($container);
对象构建器
对象构建器解析具有 #Inject
属性的属性,并尝试将适合的服务注入到属性中。如果没有提供显式的服务名称,则使用属性名称。请注意,通常建议使用简单的构造函数注入,该类是为以下情况设计的,即这不可行。
<?php class MyController { #[Inject] protected FooService $fooService; #[Inject('bar_service')] protected BarService $baz; public function doSomething() { $this->fooService->power(); } }
对象构建器可以使用缓存实例在生产中缓存所有定义的服务键。
<?php use PSX\Dependency\ObjectBuilder; use PSX\Dependency\Tests\Playground\MyContainer; use Symfony\Component\Cache\Adapter\ArrayAdapter; $container = new MyContainer(); $cache = new Pool(new ArrayCache()); $debug = false; $builder = new ObjectBuilder( $container, $reader, $cache, $debug ); $controller = $builder->getObject(MyController::class);
工厂
还可以以“Pimple”方式在容器上设置服务。通过这种方式,可以轻松扩展或覆盖现有容器。请注意,这些服务不能用于自动绑定。通常建议创建一个自定义容器并从默认容器扩展以添加新服务。
<?php use Psr\Container\ContainerInterface; $container = new \PSX\Dependency\Container(); $container->set('foo_service', function(ContainerInterface $c){ return new FooService(); }); $container->set('bar_service', function(ContainerInterface $c){ return new BarService($c->get('foo_service')); });