psx/dependency

v2.0.2 2022-01-09 01:08 UTC

This package is auto-updated.

Last update: 2024-09-09 07:12:10 UTC


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'));
});