fi1a / dependency-injection
依赖注入容器
1.0.2
2023-02-21 01:43 UTC
Requires
- php: ^7.3 || ^8
- fi1a/collection: ^2.0
- fi1a/hydrator: ^1.0
Requires (Dev)
- captainhook/captainhook: ^5.11
- phpunit/phpunit: ^9.5
- slevomat/coding-standard: ^8.6
- squizlabs/php_codesniffer: ^3.7
- vimeo/psalm: ^4.3
README
依赖注入容器,可以解析依赖、创建实例和配置类。支持构造函数、属性和方法注入。
安装
可以使用 Composer 将此包作为依赖项安装。
composer require fi1a/dependency-injection
使用容器
要使用 dependency injection 容器,首先需要在配置中设置使用 builder 创建的定义。定义的名称通常为接口名称。当请求创建对象的类型时,将使用此定义。这发生在直接从容器调用 get
方法时。在解析依赖关系时,对象也是不明确创建的。
use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; use Fi1a\Unit\DI\Fixtures\ClassC; use Fi1a\Unit\DI\Fixtures\ClassCInterface; $config = new ContainerConfig(); $config->addDefinition( Builder::build(ClassAInterface::class) ->defineClass(ClassA::class) ->getDefinition() ); $config->addDefinition( Builder::build(ClassCInterface::class) ->defineClass(ClassC::class) ->defineConstructor([1, true]) ->getDefinition() ); $container = new Container($config); $container->get(ClassCInterface::class); // ClassCInterface
对象可以以多种方式定义
- defineClass - 与特定类进行匹配;
- defineFactory - 如果实现复杂,并且最好在代码中描述,则应使用工厂方法。在使用工厂方法时,将自动解析参数中的依赖关系。
- defineObject - 返回创建的对象实例。
还提供了以下定义
- defineConstructor - 为 defineClass 定义的类设置构造函数参数;
- defineProperty - 设置对象的属性值;
- defineProperties - 设置对象属性的关联数组;
- defineMethod - 设置需要调用的对象方法,并声明参数;
- defineMethods - 设置需要调用的对象方法的关联数组,并声明参数。
如果请求的类型没有定义,容器将抛出异常 Fi1a\DI\Exceptions\NotFoundException
。
defineClass
与特定类匹配,定义构造函数参数、设置属性和调用方法
use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; $config = new ContainerConfig(); $config->addDefinition( Builder::build(ClassAInterface::class) ->defineClass(ClassA::class) ->defineConstructor([ 'parameter1' => 10, ]) ->defineProperty('property1', 100) ->defineMethod('setProperty2', [true]) ->getDefinition() ); $container = new Container($config); /** @var ClassA $object */ $object = $container->get(ClassAInterface::class); // ClassAInterface $object->property1; // 100 $object->property2; // true
defineFactory
使用闭包作为工厂方法
use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; use Fi1a\Unit\DI\Fixtures\ClassB; $config = new ContainerConfig(); $config->addDefinition( Builder::build(ClassAInterface::class) ->defineFactory(function (ClassB $classB) { $instance = new ClassA($classB); $instance->property1 = 100; $instance->property2 = true; return $instance; }) ->getDefinition() ); $container = new Container($config); /** @var ClassA $object */ $object = $container->get(ClassAInterface::class); // ClassAInterface $object->property1; // 100 $object->property2; // true
在类中使用工厂方法
use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; use Fi1a\Unit\DI\Fixtures\FactoryA; $config = new ContainerConfig(); $config->addDefinition( Builder::build(ClassAInterface::class) ->defineFactory([FactoryA::class, 'factoryStatic']) ->getDefinition() ); $container = new Container($config); /** @var ClassA $object */ $object = $container->get(ClassAInterface::class); // ClassAInterface $object->property1; // 100 $object->property2; // true
defineObject
使用已创建的对象实例
use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassB; use Fi1a\Unit\DI\Fixtures\ClassBInterface; $config = new ContainerConfig(); $config->addDefinition( Builder::build(ClassBInterface::class) ->defineObject(new ClassB()) ->getDefinition() ); $container = new Container($config); /** @var ClassB $object */ $object = $container->get(ClassBInterface::class); // ClassBInterface
di 助手
有助手 di()
可用,它返回一个用于在其他包中注册定义的容器实例。
use Fi1a\DI\Builder; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; use Fi1a\Unit\DI\Fixtures\ClassC; use Fi1a\Unit\DI\Fixtures\ClassCInterface; di()->config()->addDefinition( Builder::build(ClassAInterface::class) ->defineClass(ClassA::class) ->getDefinition() ); di()->config()->addDefinition( Builder::build(ClassCInterface::class) ->defineClass(ClassC::class) ->defineConstructor([1, true]) ->getDefinition() ); di()->get(ClassCInterface::class); // ClassCInterface
从数组创建定义
可以通过使用实现 Fi1a\DI\ArrayBuilderInterface
接口的类的方法 buildFromArray
从数组创建定义。
use Fi1a\DI\ArrayBuilder; use Fi1a\DI\Container; use Fi1a\DI\ContainerConfig; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; $config = new ContainerConfig(); $config->addDefinition( $definition = ArrayBuilder::buildFromArray([ 'name' => ClassAInterface::class, 'class_name' => ClassA::class, 'constructor' => [100, true], 'properties' => [ 'property1' => 100, 'property2' => true, ], 'methods' => [ 'setProperty1' => [100], 'setProperty2' => [true], ], ])->getDefinition() ); $container = new Container($config); /** @var ClassA $object */ $object = $container->get(ClassAInterface::class); // ClassAInterface
将定义和集合转换为数组
可以通过使用实现 Fi1a\DI\ToArrayInterface
接口的类的方法 definition
或 collection
将定义和集合转换为数组。
use Fi1a\DI\ContainerConfig; use Fi1a\DI\Builder; use Fi1a\DI\ToArray; use Fi1a\Unit\DI\Fixtures\ClassA; use Fi1a\Unit\DI\Fixtures\ClassAInterface; $config = new ContainerConfig(); $definition = Builder::build(ClassAInterface::class) ->defineClass(ClassA::class) ->defineConstructor([ 'parameter1' => 10, ]) ->defineProperty('property1', 100) ->defineMethod('setProperty2', [true]) ->getDefinition(); $config->addDefinition($definition); $toArray = new ToArray(); $array = $toArray->collection($config->getDefinitions()); // [[...], [...]] $arrayDefinition = $toArray->definition($definition); // [...]