opxcore / container
OpxCore 依赖注入容器。
Requires
- php: ^7.4
- opxcore/container-interface: ^1.0.1
Requires (Dev)
- phpunit/phpunit: ^9.5.0
README
简介
依赖注入容器是管理类依赖和执行依赖注入的强大工具。类依赖通过构造函数注入到类中,并由容器解析。
示例
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']);
制作主题的顺序
在解析某个主题时,容器首先检查注册的别名,然后检查注册的实例,并使用反射进行解析。