fi1a/dependency-injection

1.0.2 2023-02-21 01:43 UTC

This package is auto-updated.

Last update: 2024-09-21 04:58:24 UTC


README

Latest Version Software License PHP Version Coverage Status Total Downloads Support mail

依赖注入容器,可以解析依赖、创建实例和配置类。支持构造函数、属性和方法注入。

安装

可以使用 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 接口的类的方法 definitioncollection 将定义和集合转换为数组。

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); // [...]