maiorano84/league-container-config

league/container 的简单构建器

v1.0.0 2020-05-10 21:33 UTC

This package is auto-updated.

Last update: 2024-09-11 15:29:08 UTC


README

一个简单的 Builder 模式,用于从格式化的数组中创建完整的 league/container 实例。

Author Latest Stable Version Total Downloads License Build Status Code Coverage Scrutinizer Code Quality StyleCI

要求

League Container Builder 需要 PHP 7.4 或更高版本。

Composer

您可以通过运行以下命令将此包作为 Composer 依赖项安装

composer require maiorano84/league-container-config

如果您想使用最新不稳定版本,可以运行

composer require maiorano84/league-container-config:dev-master

用法

这是一个针对 The PHP League's Container 包的小型附加组件,它允许您在应用程序中传递配置对象并接收完整的 Container 实例。

有 4 个可用的构建器可供使用

  • ContainerBuilder - 主要构建器,用于实例化其构建器依赖项以及构造 Container 实例
  • DefinitionBuilder - 负责构造 Definition 实例并将其添加到其内部 DefinitionAggregate
  • InflectorBuilder - 负责构造 Inflector 实例并将其添加到其内部 InflectorAggregate
  • ServiceProviderBuilder - 负责构造 ServiceProvider 实例并将其添加到其内部 ServiceProviderAggregate

所有构建器都实现了 Maiorano\ContainerConfig\BuilderInterface,它提供了访问简单 build 方法的权限,该方法接受一个配置数组,并返回每个构建器负责构造的对象。

为什么?

如果您需要应用程序的 DI 容器可由用户配置,那么这可能有所帮助。而不是直接传递 Container 实例并让用户去解决如何连接所有内容,您可以选择配置文件(PHP、JSON、XML、YAML 等)来解析,然后一次性构建。

即使您没有计划发布需要这种层次抽象的应用程序,也可以将其用作将逻辑简化为更简洁和更具表达性的结构的方法。

除了这些原因之外,它提供的好处并不比 Container 本身处理的多。

Container 构建器

建议使用 make 工厂方法实例化 Container 构建器

use Maiorano\ContainerConfig\ContainerBuilder;

$builder = ContainerBuilder::make();

从这里,可以使用 build 命令生成 Container 对象

use League\Container\ReflectionContainer;
use Maiorano\ContainerConfig\ContainerBuilder;

$builder = ContainerBuilder::make();
$container = $builder->build([
    'definitions' => [
        AbstractInterface::class => Concrete::class, // Simple Mapping
        'name' => [ // Complete Definition structure
            'alias' => AbstractInterface::class,
            'concrete' => Concrete::class,
            'shared' => true,
            'arguments' => [Dependency::class, 'arg2', 'arg3'],
            'methods'   => ['methodName' => ['arg1', 'arg2']],
            'tags'      => ['tag1', 'tag2', 'tag3'],
        ],
    ],
    'serviceProviders' => [
        CustomServiceProvider::class,
        new UserDefinedServiceProvider,
    ],
    'inflectors' => [
        DefinitionAlias::class => 'methodName', // Simple inflector
        OtherDefinitionAlias::class => [ // Complete Inflector Structure
            'callback' => function($object){ var_dump($object); },
            'properties' => ['propery' => 'value'],
            'methods' => ['methodName' => ['arg1', 'arg2']],
        ],
    ],
    'delegates' => [
        $anotherContainerObject,
        ReflectionContainer::class,
    ],
]);

在这个示例中,将每个顶级配置块传递给相应的构建器,构建各种聚合并将它们发送到 Container 对象。

Definition 构建器

Definition 构建器只需要一个满足 DefinitionAggregateInterface 的对象。可以使用 Container Definitions 进行批量或逐个构建。

使用 build 批量生成定义

use Maiorano\ContainerConfig\DefinitionBuilder;
use League\Container\Definition\DefinitionAggregate;

$builder = new DefinitionBuilder(new DefinitionAggregate);
$aggregate = $builder->build([
    AbstractInterface::class => Concrete::class, // Simple Mapping
    'name' => [ // Complete Definition structure
        'alias' => AbstractInterface::class,
        'concrete' => Concrete::class,
        'shared' => true,
        'arguments' => [Dependency::class, 'arg2', 'arg3'],
        'methods'   => ['methodName' => ['arg1', 'arg2']],
        'tags'      => ['tag1', 'tag2', 'tag3'],
    ],
]);

在极少数需要使用定义构建器的 buildDefinition 方法的场合,可以按照以下方式逐个构造单个定义

use Maiorano\ContainerConfig\DefinitionBuilder;
use League\Container\Definition\DefinitionAggregate;

$builder = new DefinitionBuilder(new DefinitionAggregate);
$definition = $builder->buildDefinition('name', [
    'alias' => AbstractInterface::class,
    'concrete' => Concrete::class,
    'shared' => true,
    'arguments' => [Dependency::class, 'arg2', 'arg3'],
    'methods'   => ['methodName' => ['arg1', 'arg2']],
    'tags'      => ['tag1', 'tag2', 'tag3'],
]);

定义别名

尽管始终建议使用数组键或 'alias' 映射来定义别名,但 Definition 构建器也会尽力为您解析别名,以防未提供。

定义别名按以下顺序解析

  1. 配置值是否包含内嵌的 'alias' 键?如果是,则使用它。
  2. 配置键是否为非数字?如果是,则使用它。
  3. 提供的具体值是否表示有效类或接口的字符串?如果是,则使用它。
  4. 提供的具体值是否为一个对象?如果是,则使用get_class生成别名。
  5. 如果上述所有条件都不成立,则使用提供的键作为别名。

在不常见的情况下,如果提供的具体值实现了League\Container\Definition\DefinitionInterface,则构建器将假定用户意图提供自己的定义,并将绕过自己的构建过程,转而使用用户的实现。

在这种情况下,别名解析方式如下

  1. 配置值是否包含内嵌的 'alias' 键?如果是,则使用它。
  2. 配置键是否为非数字?如果是,则使用它。
  3. 如果上述所有条件都不成立,则使用现有的定义别名。

服务提供者构建器

服务提供者构建器只需要一个满足ServiceProviderAggregateInterface的对象。服务提供者可以批量或单个构建。

使用build批量生成服务提供者

use Maiorano\ContainerConfig\ServiceProviderBuilder;
use League\Container\ServiceProvider\ServiceProviderAggregate;

$builder = new ServiceProviderBuilder(new ServiceProviderAggregate);
$aggregate = $builder->build([
    CustomServiceProvider::class,
    new UserDefinedServiceProvider,
]);

在不常见的情况下,如果您需要服务提供者构建器自己的buildServiceProvider方法,可以以下方式将单个服务提供者添加到聚合中

use Maiorano\ContainerConfig\ServiceProviderBuilder;
use League\Container\ServiceProvider\ServiceProviderAggregate;

$builder = new ServiceProviderBuilder(new ServiceProviderAggregate);
$aggregate = $builder->buildServiceProvider(CustomServiceProvider::class);

重要提示
即使在使用buildServiceProvider方法的情况下,对聚合的add方法的底层调用也将返回ServiceProviderAggregate,而不是服务提供者本身。

Inflector构建器

Inflector构建器只需要一个满足InflectorAggregateInterface的对象。Inflectors可以批量或单个构建。

使用build批量生成Inflectors

use Maiorano\ContainerConfig\InflectorBuilder;
use League\Container\Inflector\InflectorAggregate;

$builder = new InflectorBuilder(new InflectorAggregate);
$aggregate = $builder->build([
    DefinitionAlias::class => 'methodName', // Simple inflector
    OtherDefinitionAlias::class => [ // Complete Inflector Structure
        'properties' => ['propery' => 'value'],
        'methods' => ['methodName' => ['arg1', 'arg2']],
    ],
]);

在不常见的情况下,如果您需要Inflector构建器自己的buildInflector方法,可以以下方式将单个Inflectors添加到聚合中

use Maiorano\ContainerConfig\InflectorBuilder;
use League\Container\Inflector\InflectorAggregate;

$builder = new InflectorBuilder(new InflectorAggregate);
$inflector = $builder->buildInflector(OtherDefinitionAlias::class, [
    'callback' => function($object){ var_dump($object); },
    'properties' => ['propery' => 'value'],
    'methods' => ['methodName' => ['arg1', 'arg2']],
]);

其他注意事项

构建模式的目的在于构建新的对象。虽然当然可以使用现有的聚合并通过Builder调用对其进行修改,但这并不推荐,并且可能被视为对构建器的一般误用。

相反,如果您需要精确控制容器的各个部分,则建议在初始构建完成后直接与结果容器或其聚合进行交互。