acclimate/container

提供各种第三方服务容器的适配器。

2.0.0 2017-05-06 18:05 UTC

This package is not auto-updated.

Last update: 2024-09-20 20:41:41 UTC


README

License Latest Stable Version Build Status Code Coverage Scrutinizer Code Quality

适应环境! 通过将第三方依赖注入容器和服务定位器适配到通用容器接口,在您的代码中使用它们。Acclimate 由 Jeremy Lindblom 创建。

简介

似乎每个框架都有自己的容器对象。它们形状和大小各异(服务定位器、服务管理器、服务容器、依赖注入(DI)容器、注册表等),但它们通常以类似的方式使用。

各种实现的广泛性使得其他框架、框架无关的库或某些应用程序难以充分发挥使用控制反转(IoC)系统的优势,因为它们或者需要

  1. 编写自己的容器实现(NIH 综合症)
  2. 长期依赖特定的第三方容器实现(并将这种依赖强加给用户,而这些用户可能已经使用不同的容器实现)
  3. 实现一个抽象层来支持一个或多个第三方容器

Acclimate 是一个库,为您完成第3点。它提供了一套最流行容器实现的适配器。这允许您将这些容器的实例适配、或“适应”到通用、规范化和互操作的接口。使用 Acclimate 允许您的框架、库或应用程序从第三方库的容器对象中检索条目。这就是互操作性!

容器接口

Acclimate 使用的 ContainerInterface 来自 psr/container 项目。它试图将容器接口的各种实现(无论是服务定位器、依赖注入容器还是类似的东西)规范化为一个简单、只读的接口,使用户能够以一致的方式从任何第三方容器中检索条目。

Acclimate v1 及之前的版本使用类似的 container-interop/container-interop 标准

ContainerInterface 看起来是这样的

namespace Psr\Container;

interface ContainerInterface
{
    /**
     * @param string $id
     * @return mixed
     * @throws NotFoundException
     * @throws ContainerException
     */
    public function get($id);

    /**
     * @param string $id
     * @return bool
     */
    public function has($id);
}

安装

使用 Composer 安装 acclimate/container 包。这将还会安装 psr/container,它提供了 ContainerInterface

警告:如果您使用开发依赖项安装 Acclimate,您将获得来自各种框架(例如,ZF、Symfony、Laravel 等)的大量包。这些包仅用于测试,以确保所有适配器类都能正确工作。当您使用 --no-dev 运行 Composer 时,它们不包括在内。

注意:我们建议使用 Composer 和 Composer 的自动加载器来加载此库。如果您不使用 Composer 的自动加载器,请确保使用 PSR-4 兼容的自动加载器,并将命名空间前缀 Acclimate\Container\ 映射到 src/ 目录,以便正确自动加载类。

基本用法

Acclimate: Container 提供了一个用于将容器对象适配到规范化的 ContainerInterfaceContainerAcclimator 对象。从设计模式的角度来看,它本质上是一个适配器工厂。

以下是使用 ContainerAcclimator 的示例

<?php

// Require the Composer autoloader
require 'vendor/autoload.php';

use Acclimate\Container\ContainerAcclimator;

// Create a `Pimple` container and store an `SplQueue` object in it
$pimple = new Pimple();
$pimple['queue'] = function() {
    $queue = new SplQueue();
    $queue->enqueue('Hello!');
    return $queue;
};

// Create a `ContainerAcclimator` and use it to adapt the `Pimple` container to the Acclimate `ContainerInterface`
$acclimator = new ContainerAcclimator;
$container = $acclimator->acclimate($pimple);

// Use the adapted container via the common interface to fetch the queue object
$queue = $container->get('queue');
echo $queue->dequeue(); // Look! The queue object still works!
#> Hello!

现在您可以使用您最喜欢的框架中的容器,并将其适应到您的其他代码中。:-)

容器装饰器

实现ContainerInterface接口的容器的默认行为是在使用get()方法检索容器中实际不存在的条目时抛出Psr\Container\NotFoundExceptionInterface异常。在某些情况下,您可能希望将此默认行为更改为执行其他操作(例如,返回null)。容器装饰器允许您轻松地修改容器的行为。acclimate\container自带3个装饰器(NullOnMissContainerCallbackOnMissContainerFailoverOnMissContainer),但允许您通过扩展Acclimate\Container\Decorator\AbstractContainerDecorator轻松地创建自己的装饰器。

以下是如何使用NullOnMissContainer装饰器的示例

<?php

// Require the Composer autoloader
require 'vendor/autoload.php';

use Acclimate\Container\ArrayContainer;
use Acclimate\Container\Decorator\NullOnMissContainer;
use Psr\Container\NotFoundExceptionInterface;

// Create an empty, basic container following the `ContainerInterface`
$container = new ArrayContainer();

// Normally, this container will throw an exception on missing items
try {
    $item = $container->get('foo');
} catch (NotFoundExceptionInterface $e) {
    echo $e->getMessage() . "\n";
}
# There is no entry found in the container for the identifier "foo".

// Decorate the container so that null is returned instead of throwing an exception
$container = new NullOnMissContainer($container);
$item = $container->get('foo');
var_dump($item);
#> NULL

组合容器

如果您需要从两个或更多不同的容器对象中获取数据,则可以创建组合容器。为了下面的示例,我们将假设您有一个存储在变量$sfContainer中的Symfony Container,以及一个存储在变量$zfContainer中的Zend ServiceManager

use Acclimate\Container\ContainerAcclimator;
use Acclimate\Container\CompositeContainer;

// First, let's acclimate these containers
$acclimator = new ContainerAcclimator;
$sfContainer = $acclimator->acclimate($sfContainer);
$zfContainer = $acclimator->acclimate($zfContainer);

// Now, we will put these two containers together
$container = new CompositeContainer([$sfContainer, $zfContainer]);

// When we execute the `has()` method of the container, it will return `true`
// if at least one of these containers contains an item identified by "foo"
$exists = $container->has('foo');

这本质上是一种支持容器链式调用的方式,但使用的是组合设计模式而不是命令链模式。您还可以使用FailoverOnMissContainer装饰器来支持链式调用。

支持的容器

此外,Silex Application和其他从Pimple派生的项目也可以与Acclimate一起使用。

已弃用的容器

对以下容器的支持已在1.1版本中弃用,并在2.0版本中删除

如果我不使用的容器不受支持怎么办?

请考虑提交一个包含您的容器适配器和相应测试的Pull Request。

但在您做到这一点之前,您可以自己创建适配器(实际上非常容易做到,只需查看附带的适配器即可),并使用ContainerAcclimator::registerAdapter()方法将适配器连接到Acclimate。您需要提供适配器类和您想要能够适配的容器的基础类或接口的完全限定名称(FQCN)。

假设您有一个实现Your\Favorite\ContainerInterface$container对象,并且您已经编写了一个名为Your\Favorite\ContainerAdapter的适配器类,以下是如何在Acclimate中使这些工作起来的示例

use Acclimate\Container\ContainerAcclimator;

// Instantiate the `ContainerAcclimator` and register your custom adapter
$acclimator = new ContainerAcclimator;
$acclimator->registerAdapter('Your\Favorite\ContainerAdapter', 'Your\Favorite\ContainerInterface');

// Use Acclimate to adapt your container
$adaptedContainer = $acclimator->acclimate($container);

资源