bluepsyduck/zend-autowire-factory

该包已废弃,不再维护。作者建议使用bluepsyduck/laminas-autowire-factory包代替。

一个允许像在Symfony中一样进行自动装配的Zend工厂实现。

1.1.0 2019-07-08 16:42 UTC

This package is auto-updated.

Last update: 2020-11-11 09:56:35 UTC


README

GitHub release (latest SemVer) GitHub Codecov

已弃用:请使用包 bluepsyduck/laminas-autowire-factory

bluepsyduck/laminas-autowire-factory 包具有与该包相同的功能,唯一的区别是命名空间。除了导入之外,无需任何更改。

此库提供了一些帮助将服务类自动装配的工厂,以减少实际工厂的使用。

AutoWireFactory

AutoWireFactory 使用实际服务类的构造函数进行反射,以确定如何解析依赖关系并创建实际服务。该工厂采用 Symfony的自动装配方法,特别是处理相同类型的多个实现。

解析策略

根据参数的类型提示,工厂使用以下策略来解析构造函数的参数。容器中可用的第一个别名将被用来解析依赖关系。如果没有可用的别名,将引发异常。

每个参数都是独立解析的,因此它们可以以任何方式组合。

具有类类型提示的参数

示例: __construct(FancyClass $fancy)

如果参数有类名作为类型提示,则在容器中检查以下别名

  1. FancyClass $fancy:类名和参数名的组合。这允许有多个相同接口的实现,如Symphony文档所述。
  2. FancyClass:将类注册到容器中的“默认”情况。
  3. $fancy:仅使用参数名作为后备。

将使用容器提供的第一个别名。

具有标量类型提示的参数

示例: __construct(array $fancyConfig)

如果参数使用标量类型提示,例如将配置值拉入服务,则检查以下别名

  1. array $fancyConfig:类型和参数名的组合,与类类型提示相同。
  2. $fancyConfig:仅使用参数名作为后备。

请注意,类型本身(例如,array)不作为别名使用。

没有类型提示的参数

示例:__construct($fancyParameter)

由于信息缺失,在这种情况下只能检查一个别名。

  1. $fancyParameter:回退是唯一可能的别名。

将AutoWireFactory作为AbstractFactory

除了使用FactoryInterface,将AutoWireFactory作为显式工厂在容器配置中,它还实现了AbstractFactoryInterface:如果您将此工厂作为抽象工厂添加,它将尝试自动连接所有内容。这将使配置容器主要变得过时,除非使用标量值或多个实现(其中参数名称是容器别名的部分)的参数。

缓存

AutoWireFactory使用反射来解决依赖项。为了加快速度,工厂在文件系统中建立缓存以避免在每个脚本调用中使用反射。要启用缓存,请添加以下行,例如在config/container.php文件中:

\BluePsyduck\ZendAutoWireFactory\AutoWireFactory::setCacheFile('data/cache/autowire-factory.cache.php');

ConfigReaderFactory

为了进一步使自定义工厂过时,ConfigReaderFactory能够将应用程序配置的值提供给容器,例如与自动连接一起使用。

用法

ConfigReaderFactory需要将应用程序配置作为数组添加到容器中。如果配置的别名与默认的“config”不同,请调用ConfigReaderFactory::setConfigAlias('yourAlias')来设置别名。

然后,使用readConfig(string ...$keys)函数(或new ConfigReaderFactory(string ...$keys))来读取容器的配置值,其中$keys是要在配置中到达所需值的数组键。请注意,如果键未设置,工厂将触发异常。

AliasArrayInjectorFactory

AliasArrayInjectorFactory从配置中读取别名数组(使用ConfigReaderFactory),并为这些别名创建所有实例,然后返回以注入到其他服务中。所有别名都必须为容器所知。

要在容器配置中使用此工厂,只需调用injectAliasArray(string ...$configKeys)(或new AliasArrayInjectorFactory(string ...$configKeys))即可。

示例

以下示例应显示如何使用AutoWireFactoryConfigReaderFactory来自动连接服务类。

假设我们有以下应用程序配置,我们希望从中获取值

[
    'fancy-service' => [
        'fancy-property' => 'Hello World!',
        'fancy-adapters' => [
            FancyAdapterAlpha::class,
            FancyAdapterOmega::class,
        ],
    ],
]

我们希望自动连接以下服务类

class FancyService {
    public function __construct(FancyComponent $component, string $fancyProperty, array $fancyAdapters) {
    }
}

class FancyComponent {}
class FancyAdapterAlpha {}
class FancyAdapterOmega {}

以下配置可以在不编写任何工厂的情况下用于容器

<?php 

use BluePsyduck\ZendAutoWireFactory\AutoWireFactory;
use Zend\ServiceManager\Factory\InvokableFactory;
use function BluePsyduck\ZendAutoWireFactory\injectAliasArray;
use function BluePsyduck\ZendAutoWireFactory\readConfig;

return [
    'dependencies' => [
        'factories' => [
            // Enable auto-wiring for the service itself.
            FancyService::class => AutoWireFactory::class,
            
            // FancyComponent does not need any factory as it does not have a constructor.
            // Both InvokableFactory and AutoWireFactory are usable here.
            FancyComponent::class => InvokableFactory::class,
            FancyAdapterAlpha::class => InvokableFactory::class,
            FancyAdapterOmega::class => InvokableFactory::class,
            
            // Enable the scalar property for auto-wiring into the service.
            // In this example, the factory would fetch "Hello World!" from the config.
            'string $fancyProperty' => readConfig('fancy-service', 'fancy-property'),
            
            // Inject an array of other services through their aliases into the service.
            // In this example, instances of FancyAdapterAlpha and FancyAdapterOmega would be injected. 
            'array $fancyAdapters' => injectAliasArray('fancy-service', 'fancy-adapters'),
        ],
    ],
];

如果使用AutoWireFactory作为抽象工厂,此配置可以进一步缩短

<?php 

use BluePsyduck\ZendAutoWireFactory\AutoWireFactory;
use function BluePsyduck\ZendAutoWireFactory\injectAliasArray;
use function BluePsyduck\ZendAutoWireFactory\readConfig;

return [
    'dependencies' => [
        'abstract_factories' => [
            // Will auto-wire everything possible to be auto-wired, in our case both FancyService and FancyComponent.
            AutoWireFactory::class,
        ],
        'factories' => [
            // Any aliases using property names cannot be handled by the AutoWireFactory and must still get listed.
            'string $fancyProperty' => readConfig('fancy-service', 'fancy-property'),
            'array $fancyAdapters' => injectAliasArray('fancy-service', 'fancy-adapters'),
        ],
    ],
];

当然,如果自动连接由于更复杂的初始化要求而不可行,始终可以向任何服务添加具体工厂。