mmoreram/doppo

小型依赖注入容器

dev-master / 1.0.x-dev 2014-10-14 19:03 UTC

This package is auto-updated.

Last update: 2024-08-29 04:19:48 UTC


README

Build Status SensioLabsInsight Latest Stable Version Latest Unstable Version License

哦,不……另一个用PHP编写的依赖注入容器?

事实上是的,但这个项目的目的是学术性的,旨在讨论关于构建依赖注入容器最佳方法的一些有趣话题。

Doppo是一个基本的DIC实现,实现了一些功能(没有新功能,只是我认为最重要的和有用的),使用TDD开发,经过几次重构和几次架构变更。

那么,它究竟是什么呢?让我们看看它的功能。

容器

Doppo容器需要用两个必需的参数来构建。首先,我们需要定义我们想要编译的配置,其次,我们需要定义调试标志。

use Doppo\Doppo;

$configuration = [];
$debug = true;

$doppo = new Doppo(
    $configuration,
    $debug
);

这是一个空的Doppo容器,我们可以看到配置是空的,并且是在调试模式下创建的。这些信息不能再修改,所以它就像容器实例的指纹。

We could not define this object as immutable because when is compiled, the
object's state changes from an external point of view.

这个$configuration值定义了容器应该如何编译以及所有定义的服务应该如何构建。让我们看看完整的定义。

定义

$configuration = array(
    'my_service' => array(
        'class' => 'My\Class\Namespace',
        'arguments' => array(
            '@my_other_service',
            '~my_parameter',
            'simple_value',
        )
    ),
    'my_other_service' => array(
        'class' => 'My\Class\Namespace',
    ),
    'my_parameter' => 'parameter_value',
);

配置允许两种类型的元素:服务和参数。从DIC的角度来看,它们之间的区别在于任何服务定义都必须包含一个类值,所以如果定义是一个数组,并且存在class键,这将被视为一个服务。

否则,将视为一个参数。

正如你所看到的,当我们定义服务的参数时,我们可以使用前缀@引用另一个服务,我们也可以使用前缀~引用参数值,或者我们可以直接传递一个原始值,如字符串、数组或对象。

将依赖项传递给服务的方式只能是构造函数。一些其他容器允许您使用setter或公共变量来构建服务,但这个不行。考虑到服务依赖项必须在构造函数中注入,否则它不是依赖项而是配置,容器应该只了解构建,而不是配置,至少在特定实现之前是这样。

编译

一旦容器用配置和调试模式构建,我们必须编译它。在这种情况下,容器将内部构建一个结构来正确地提供服务实例和参数值。

use Doppo\Doppo;

$configuration = array(
    'my_service' => array(
        'class' => 'My\Class\Namespace',
        'arguments' => array(
            '@my_other_service',
            '~my_parameter',
            'simple_value',
        )
    ),
    'my_other_service' => array(
        'class' => 'My\Class\Namespace',
    ),
    'my_parameter' => 'parameter_value',
);
$debug = true;

$doppo = new Doppo(
    $configuration,
    $debug
);

$doppo->compile();

容器编译只能进行一次。如果我们编译了一个已编译的容器,将抛出异常。

用法

一旦容器编译完成,您可以使用get方法检索任何定义的服务实例,使用getParameter方法检索任何定义的参数值。

$myServiceInstance = $doppo->get('my_service');
$myParameterValue = $doppo->getParameter('my_parameter');

当您检索服务实例时,它只构建一次。这意味着在内部,当任何服务被请求并构建时,在返回之前,结果实例将存储在本地。当服务再次被调用时,现有的实例将被返回而不是再次构建它。

缓存

这里的问题是,容器在每次需要时都会被构建和编译。这意味着在每次执行时都会处理和检查容器,这使得它非常低效。

此包还提供了一个主类Doppo的扩展。它被称为CacheableDoppo,构建方式如下。

use Doppo\Doppo;

$configuration = [];
$debug = true;
$cachePath = '/tmp/doppo.cache.php';

$doppo = new Doppo(
    $configuration,
    $debug,
    $cachePath
);

这个新类与之前的类工作方式相同,都实现了相同的接口ContainerInterface,但这个类在第一个之上增加了一个缓存层。当容器被编译时,会生成一个缓存文件,并将其存储在指定的位置,这是最后一个构造函数参数指定的。

每次容器需要构建时,如果缓存文件已经创建,则会加载这个文件,并提供一组定义所有服务构建规范的方法。

装饰器

容器也可以被装饰。装饰器类也必须实现ContainerInterface,并且可以在不改变旧实现的情况下,向指定的接口添加一些行为。

LoggableDecorator

这个装饰器根据容器的调试模式记录所有与公共容器API的外部交互。

use Doppo\Doppo;

$configuration = [];
$debug = true;
$cachePath = '/tmp/doppo.cache.php';
$logger = new Logger();

$doppo = new LoggableDecorator(
    new Doppo(
        $configuration,
        $debug,
        $cachePath
    ),
    $logger
);

Logger实例必须实现由包Psr\Log提供的Psr\Log\LoggerInterface。您可以在这些包列表中看到一些公共实现。