catacgc/juice-di-container

小巧、快速、功能丰富的 PHP 5.2 依赖注入

dev-master 2013-03-10 16:01 UTC

This package is not auto-updated.

Last update: 2024-09-28 13:35:39 UTC


README

功能

  • 小巧且快速
  • 与 PHP 5.2 兼容
  • 比大多数其他 PHP DI 容器实现(如 Symfony2、ZF2)更轻量级
  • 流畅的服务定义接口
  • 标记服务定义
  • 循环依赖解析器
  • 实现 ArrayAccess 以便在测试中使用数组轻松模拟

安装

容器由单个文件组成,src/Container.php

对于 PHP 5.2,您可以使用 curl / wget / git 下载该文件,并简单地 require 它

对于 PHP 5.3 及以上版本,您可以使用 composer

{
    "catacgc/juice-di-container": "dev-master"
}

在克隆存储库后,您可以使用 phpunit 运行测试

phpunit -c phpunit.xml.dist

创建容器

require 'src/Container.php';
$container = new JuiceContainer();

容器值

容器将参数存储为键 => 值,但其主要优势是服务运行时的连接

服务是通过使用两个特殊的容器值创建的

  • JuiceDefinition 实例
  • 有效的 PHP 回调(包括闭包,从 PHP 5.3 开始),它们接收容器实例作为其唯一的参数,以便引用其他参数或服务

参数

$container['mysql_host'] = 'localhost';
$container['mysql_user'] = 'username';
$container['mysql_pass'] = 'password';
$container['mysql_port'] = 3306;

echo $container['mysql_port'];

服务定义

由于为每个服务创建工厂方法很繁琐,容器特别处理了一个方便创建复杂服务的 JuiceDefinition 类型

您可以在所有 JuiceDefinition 方法参数中使用 @service_id 符号引用其他服务或参数

API

// simple class
$container['conn'] = new JuiceDefinition('Connection');   // => new Connection()

// or using the fluent interface to do the same
$container['conn'] = JuiceDefinition::create('Connection')

// replacing the class name
$container['conn'] = JuiceDefinition::create('Connection')->className('ChangedMyMindConnection')

// providing arguments
JuiceDefinition::create('Connection', array('username', 'password'))

// replacing arguments
JuiceDefinition::create('Connection')->arguments(array('username1', 'password1'))

// replacing specific argument
JuiceDefinition::create('Connection')->argument(0, 'new_username')

// calling methods
JuiceDefinition::create('Connection', array('user', 'pass'))
    ->call('setDb', array('db_name'))

构造函数注入

$container['conn'] = new JuiceDefinition('MysqlConnection', array('@mysql_user', '@mysql_password'));
$container['dbal'] = new JuiceDefinition('Dbal', array('@conn'));

现在调用 $dbal = $container['dbal'] 等同于调用

$connection = new MysqlConnection('username', 'password');
$dbal = new Dbal($connection);

设置器注入

$container['conn'] = new JuiceDefinition('Connection');
$container['dbal'] = JuiceDefinition::create('Dbal')->call('setConnection', array('@conn'))

扩展定义

$container['conn'] = JuiceDefinition::create('MysqlConnection');

// now in another module, in its configuration 

$connDef = $container->raw('conn');
$connDef->className('MysqlWrapperConnection');

从回调添加服务

传递给容器的每个可调用对象都将被调用,当客户端检索时,容器实例作为其唯一的参数,返回值将代表关联的 id 的实际服务/参数。

$container['db'] = array('Factory', 'createDbConnection');
$pdoObject = $container['db']; //actually calls the factory method

其中工厂将如下所示

class Factory
{
    public static function createDbConnection($container) // <- note the container parameter
    {
        return new PDO(
            sprintf('mysql:host=%s;dbname=%s', $container['mysql_host'], $container['mysql_dbname']),
            $container['mysql_user'],
            $container['mysql_pass']
        );
    }
}
  • 注意:所有回调都接收容器作为其唯一参数

服务别名

$container['mysql_default_connection'] = JuiceDefinition::create('MysqlConnection', array('@mysql_username', '@mysql_password'));
$container['connection'] = '@mysql_default_connection';

现在 $container['connection']$container['mysql_default_connection'] 将引用同一服务实例

转义回调和其他特殊类型

有时您的意图是实际上将回调作为真正的参数添加,而不是创建服务定义

为此,有一个特殊的包装类型 JuiceParam,您可以使用它

$container['invalid_callback'] = 'strpos';
echo $container['invalid_callback'];

会引发错误,因为对于 PHP,strpos 是可调用类型,容器将尝试用 strpos($container) 调用它以检索所谓的服务实例

$container['callback'] = new JuiceParam('strpos');
echo $container['callback']; //now echoes the expected 'strpos' string

锁定行为

从容器检索参数或服务后,您将无法再添加、覆盖或扩展服务。例如

$container['param'] = 1;
echo $container['param'];

$container['param'] = 2; //throws exception

这是故意的,为了在使用之前强制配置和稳定的行为:一旦您使用了服务,您就可以确信您在整个应用程序中都有相同的服务。

出于测试目的,您可以通过调用 $container->unlock(); 来覆盖此行为

创建新的服务实例

默认行为是在每次调用时检索相同的服务实例。

如果您希望动态创建新服务实例,请使用 build 方法

$conn1 = $container->build($container->raw('conn'));
$conn2 = $container->build($container->raw('conn'));

完整示例用法

/**
* Configuration
*/

$container = new JuiceContainer();

$container['cache_dir'] = '/tmp/cache';
$container['memcache_host'] = 'localhost';
$container['memcache_port'] = 11211;

$container['main_cache'] = JuiceDefinition::create('Memcache')
    ->call('connect', array('@memcache_host', '@memcache_port'));

$container['slow_cache'] = JuiceDefinition::create('FileCache')
    ->arguments(array('@cache_dir'));

$container['two_level_cache'] = JuiceDefinition::create('TwoLevelCache')
    ->arguments(array('@main_cache', '@slow_cache'));

$container['cache'] = '@two_level_cache';

/**
* Usage
*/

$cache = $container['cache'];

if ($data = $cache->load('expensive_operation_id')) {
    //cache hit
    return;
}

$cache->save('expensive_operation_id', do_expensive_operation(), 60);