dsawardekar / encase-php
PHP的轻量级IOC容器
Requires (Dev)
- phpunit/phpunit: ~3.7.0
This package is not auto-updated.
Last update: 2024-09-14 15:28:58 UTC
README
PHP的轻量级IOC容器。
Encase是一个用于在PHP应用程序中实现依赖注入的库。它提供了一个轻量级的IOC容器,用于管理类之间的依赖关系。它被编写来帮助在框架之外连接领域对象,以构建更快的测试套件。
Ruby实现在这里:here。
特性
- 存储对象、工厂和单例
- 声明式语法来指定依赖
- 简单的API来配置容器
- 支持嵌套容器
- 支持延迟初始化
- 初始化器
用法
考虑一个Worker
类,它依赖于一个Logger
。我们希望这个依赖在创建Worker时可用。
首先,我们创建一个容器对象并声明依赖。
<?php use Encase\Container; $container = new Container(); $container->object('logger', new Logger()) ->factory('worker', 'Worker');
然后,我们使用needs
函数声明Worker依赖于logger
。它返回与我们在容器上注册的键相对应的键数组。
<?php class Worker { function needs() { return array('logger'); } }
就是这样!现在我们可以通过在容器上查找worker
键来创建一个新的Worker
。
<?php $myWorker = $container->lookup('worker'); $myWorker instanceof Worker; // true
Worker
实例会自动获取对logger
的引用。
<?php $myWorker->logger instanceof Logger; // true
容器配置
容器通过函数object
、factory
或singleton
进行配置。容器项目存储在容器内部的关联数组中,并在稍后用于查找对象。
<?php $container->object(...); $container->factory(...); $container->singleton(...);
以下列出您可以在容器中存储的项目类型。
对象
对象是在系统中已创建的现有值。可以是字符串
、数字
或不需要实例化的任何值。
它们存储在容器中,并且未经任何修改就返回。要存储对象,请调用object
函数。并传递要存储的对象的字符串键以及对象本身。
<?php $container->object('key', existingValue);
工厂
工厂容器项是一个Classpath
字符串。在每次查找时,都会使用它创建该Class
的新实例,并自动注入其依赖项。
要存储此类,请使用factory
函数。并传递要实例化的Class
的完整类路径。
<?php $container->factory('key', 'FactoryClass');
单例
单例类似于工厂。然而,它在第一次查找时缓存创建的实例,并在随后的查找中返回该实例。
使用singleton
函数存储单例Class
的路径。
<?php $container->singleton('key', 'SingletonClass');
声明依赖
要指定类的依赖项,您使用needs
函数。它必须返回与容器中存储的键对应的字符串数组。
<?php class Worker { function needs() { return array('one', 'two', 'three'); } }
您可以选择使用INeeds
接口来声明需求。
<?php class Worker implements INeeds { function needs() { return array('one', 'two', 'three'); } }
延迟初始化
Encase允许延迟存储依赖项。如果依赖项在容器配置时不可用,这很有用。但在查找之前将准备好。
通过将closure
或callable
传递给容器而不是值来执行延迟初始化。在这里,key
的callable
将在第一次查找之前执行。
<?php // with $callables $container->object('key', $callable); // with an anonymous function $container->object('key', function($container) { return 'value'; });
闭包或可调用对象接受一个等于容器对象本身的参数。您可以使用这个参数根据容器中的其他对象或系统中的其他地方的条件性地解析值。
初始化器
初始化器在处理不使用Encase容器的外部库对象时非常有用。这些对象没有声明它们的needs
,但在使用之前仍然需要初始化。
初始化器方法接受要初始化的对象的键和一个用于初始化对象的$callable
。可调用对象将接收两个参数,从容器中查找的对象的值和容器本身。
对于object
和singleton
类型的项,初始化仅在第一次查找时发生。而factory
类型的项,每次从容器中查找新实例时都会运行其初始化器。
下面的代码将Currency
对象存储在容器中。为此对象添加了一个初始化器,以确保每次实例化时都会设置格式化程序。
<?php $container->factory('currency', 'Currency'); $container->factory('formatter', 'NumberFormatter'); $container->initializer('currency', array($this, 'initCurrency')); function initCurrency($currency, $container) { $currency->setFormatter($container->lookup('formatter')); }
打包器
打包器是方便的辅助工具,可以将一个特性的依赖项作为一个单元进行分组。例如,如果Options
特性由OptionsStore
、OptionsPage
和OptionsValidator
类组成,每次需要使用此Options
特性时,您都需要在容器中声明这些依赖。
使用打包器对象可以将这些依赖添加到容器中。打包器应在下面的onInject
函数中设置其依赖项,如下所示:
<?php class OptionsPackager { function onInject($container) { $this->container ->factory('optionsStore', 'OptionsStore') ->factory('optionsValidator', 'OptionsValidator') ->factory('optionsPage', 'OptionsPage'); } }
现在,当您需要该特性时,只需将打包器添加到容器中即可。
<?php $container->packager('optionsPackager', 'OptionsPackager')
packager
本身将作为单例注册到容器中,可以通过其键查找。
嵌套容器
容器也可以嵌套在其他容器中。这允许在应用程序的不同上下文中对依赖项进行分组。在查找键时,如果子容器中没有找到键,则查询父容器。
<?php $parent = new Container(); $parent->object('logger', new Logger()) ->factory('worker', 'Worker'); $child = $parent->child(); $child->factory('worker', 'CustomWorker'); $child->lookup('logger'); // from parent container $child->lookup('worker'); // from child container
在这里,child
将使用CustomWorker
来解析worker
。而logger
将从parent
容器中查找。
公共属性
对于每个声明的need
,Encase将在注入的对象上创建相应的公共属性。同时,也会将一个container
属性注入到类中,以便在运行时查找其他依赖。
<?php class Worker { function needs() { return array('one', 'two', 'three'); } } worker = container->lookup('worker'); worker->one; worker->two; worker->three; worker->container; // reference to the container object
生命周期
容器项在其依赖项注入后提供了onInject
事件钩子。任何后注入的初始化都可以在这里执行。
<?php class Worker implements { function needs() { return array('logger'); } function onInject($container) { $this->logger->log('Worker is ready'); } }
测试
Encase简化了对象的测试。由于对象存储在容器中,您可以深入到对象的依赖图内部,并用一个模拟对象替换一个昂贵的依赖。
在早期示例中,为了测试日志器确实被worker调用,我们可以将worker注册为一个mock
对象。然后验证这个mock是否被适当地调用。
<?php function test_it_logs_message_to_the_logger() { $mock = $this->getMock('Logger', 'log'); $mock->expects($this->once()) ->method('log') ->with($this->equalTo('something')); $container = new Container(); $container->factory('worker', 'Worker'); $container->object('logger', $mock); $worker = $container->lookup('worker'); $worker->start(); }
安装
将此行添加到您的composer.json
中。
{ "require": { "dsawardekar/encase-php": "~0.1.0" } }
然后执行
$ composer install
系统要求
Encase已测试,可在以下平台上运行。
- PHP 5.3
- PHP 5.3.3
- PHP 5.4
- PHP 5.5
- PHP 5.6
贡献
有关Portkey的贡献指南,请参阅贡献指南。
许可
MIT许可证。版权所有©2014 Darshan Sawardekar