catacgc / juice-di-container
小巧、快速、功能丰富的 PHP 5.2 依赖注入
Requires
- php: >=5.2
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);