opxcore/container

OpxCore 依赖注入容器。

1.0.3 2020-12-23 19:36 UTC

This package is auto-updated.

Last update: 2024-09-24 04:15:07 UTC


README

Build Status Coverage Status Latest Stable Version Total Downloads License

简介

依赖注入容器是管理类依赖和执行依赖注入的强大工具。类依赖通过构造函数注入到类中,并由容器解析。

示例

class Controller
{
    protected Repository $repository;
    
    public function __construct(Repository $repository)
    {
        $this->repository = $repository;
    }
}

调用 $container->make(Controller::class) 等同于 new Controller(new Repository)。这个惊人的特性通过 零配置 自动解析所有依赖注入。对于这个例子,如果 Repository 有自己的依赖,它将以相同的方式被解析。

安装

composer require opxcore/container

创建

您可以通过多种方式创建容器

$container = Container::setContainer(new Container);

$container = Container::getContainer();

在所有这些情况下,Container::getContainer() 总是返回相同的容器实例。

如果您想自己创建和处理容器(或多个容器),只需使用 $container = new Container 并按需处理此容器实例。

将绑定注册到容器中

基本绑定到容器的样子

$container->bind($abstract, $concrete, $parameters);

$abstract 是包含类名或要解析的名称简写的字符串。

$concrete 是包含类名或返回对象的 callable 的字符串,该对象将解析为名称。解析时将传递容器实例和参数给可调用。

$parameters 是数组或返回参数数组的可调用,用于解析(见下文)。默认值为 null 表示不会绑定任何参数。

示例

简单使用

$container->bind('logger', Logger::class);

// New instance of Logger with resolved dependencies will be retuened.
$logger = $container->make('logger');

将接口绑定到其实例

我们有一个 Controller 类,它依赖于某些 RepositoryInterface,而 FileRepository 实现了它

class Controller
{
    protected RepositoryInterface $repository;
    
    public function __construct(RepositoryInterface $repository)
    {
        $this->repository = $repository;
    }
}
class FileRepository implements RepositoryInterface
{
    protected string $path;
    
    public function __construct(string $path)
    {
        $this->path = $path;
    }
}

现在我们将 FileRepository::class 绑定到 RepositoryInterface::class,因此当某个类依赖于 RepositoryInterface 时,它将被解析为 FileRepository,并且将指定值传递给 path 参数。

$container->bind(RepositoryInterface::class, FileRepository::class, ['path'=>'/data/storage']);

$controller = $container->make(Controller::class);

绑定参数

您可以将参数绑定到容器中以便解析。它可以用作原始绑定或类绑定

// When FileRepository dependencies would be resolving, given value would be passed to `path` attribute.
$container->bindParameters(FileRepository::class, ['path' => '/data/storage']);

// When Controller would be resolved a FileRepository would be given as RepositoryInterface dependency.
$container->bindParameters(Controller::class, [RepositoryInterface::class => FileRepository::class]);

单例

单例方法将一个类或接口绑定到容器中,它应该只解析一次。第一次解析并存储在容器中,因此后续调用容器时将返回相同的对象实例。

$container->singleton(RepositoryInterface::class, FileRepository::class, ['path'=>'/data/storage']);

// Each time when RepositoryInterface needs to be resolved
// the same instance of FileRepository would be given.
$repository = $container->make(RepositoryInterface::class);

别名

别名是解析的另一种名称。

$container->singleton(RepositoryInterface::class, FileRepository::class, ['path'=>'/data/storage']);
$container->alias(RepositoryInterface::class, 'repo');

// This would return FileRepository instance.
$container->make('repo');

实例

您可以将任何对象或值注册到容器中。

$container->instance('path', '/data/storage');
// '/data/storage' would be returned
$container->make('path');

$container->instance(RepositoryInterface::class, new FileRepository('/data/storage'));
// FileRepository would be returned
$container->make(RepositoryInterface::class);

解析

解析某个名称时,您可以通过将参数传递给 make() 函数来将其附加到解析主题。

$container->bind(RepositoryInterface::class, FileRepository::class);
$container->make(RepositoryInterface::class, ['path'=>'/data/storage']);

制作主题的顺序

在解析某个主题时,容器首先检查注册的别名,然后检查注册的实例,并使用反射进行解析。