zeelot / kohana-dependencies
为Kohana 3.x提供的依赖注入容器模块
Requires
- php: >=5.3.3
- composer/installers: ~1.0
- kohana/core: >=3.3
Requires (Dev)
- bossa/phpspec2-expect: dev-master
- kohana/koharness: dev-master
- mikey179/vfsstream: ~1.3
- phpspec/phpspec: dev-master
This package is auto-updated.
Last update: 2020-01-21 02:31:23 UTC
README
一个简单的Kohana 3.3.x依赖注入容器
- 作者:Jeremy Lindblom (jeremeamia)
- 版本: 0.7
关于依赖注入和依赖注入容器
依赖注入是一种遵循控制反转 (IoC) 或依赖倒置原则的方法。依赖注入容器 (DIC) 是一个用于管理依赖并简化依赖注入维护的组件。使用依赖注入的一些主要论据包括它
- 简化单元测试和模拟(或使其成为可能)
- 解耦对象实例化和使用
- 允许更好地分离关注点并提高对象内聚度
- 减少单例类的使用和需求,而单例类被许多人认为是不好的
有关依赖注入的信息,您应阅读以下文章
- https://martinfowler.com.cn/articles/injection.html
- http://fabien.potencier.org/article/11/what-is-dependency-injection
- http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator
- http://misko.hevery.com/2008/09/10/where-have-all-the-new-operators-gone
- http://misko.hevery.com/2008/09/30/to-new-or-not-to-new (很棒)
使用此依赖注入容器
容器有一个->get($key)
方法,用于获取由$key
标识的对象的实例。容器使用您设置的依赖定义以正确的方式创建对象实例,包括所有必要的依赖。
使用示例
假设您在一个控制器上下文中,并且它有一个容器实例,您可以这样做...
$mailer = $this->container->get('swift.mailer');
这能给您带来什么?好吧,假设您已经设置了一些杀手级依赖定义(稍后展示),它将返回一个完全初始化的SwiftMailer对象实例,其中包含所有依赖和配置。如果您之前使用过SwiftMailer,您知道手动创建实例很痛苦。
或者...您会如何实例化一个需要会话和事件调度器的User Model(使用任何类似ORM的库或数据库驱动程序),同时保持适当的控制反转,但又不希望手动实例化它带来的麻烦?您想要这样做吗?太棒了!一旦配置完成,它可能看起来像这样
$user = $this->container->get('model.user')->find($this->request->param('user_id));
您的想象力只受限于您的想象...和PHP。
依赖定义设置
class
:要创建的类的名称。path
:包含类的文件的路径。如果没有提供,将尝试自动加载类。constructor
:用于创建类的函数。如果没有提供,将使用__construct()
。arguments
:传递给构造函数方法的参数。shared
:共享设置确定对象是否将被缓存。默认为FALSE
。methods
:需要调用创建对象的额外方法(及其参数)。
创建容器
您可以从依赖定义数组(即从配置文件)创建容器。
// Creation Code
$definitions = Dependency_Definition_List::factory()
->from_array(Kohana::config('dependencies')->as_array());
$container = new Dependency_Container($definitions);
以下是一个示例配置文件
// Config File
return array(
'session' => array(
'_settings' => array(
'class' => 'Session',
'constructor' => 'instance',
'arguments' => array('@session.driver@'),
'shared' => TRUE,
),
),
'model' => array(
'_settings' => array(
'class' => 'Model',
'constructor' => 'factory',
),
'user' => array(
'_settings' => array(
'arguments' => array('user'),
'methods' => array(
array('set_session', array('%session%')),
),
),
),
),
'swift' => array(
'transport' => array(
'_settings' => array(
'class' => 'Swift_SmtpTransport',
'path' => 'vendor/swiftmailer/lib/classes/Swift/SmtpTransport',
'arguments' => array('@email.host@', '@email.port@'),
'methods' => array(
array('setEncryption', array('@email.encryption@')),
),
),
),
'mailer' => array(
'_settings' => array(
'class' => 'Swift_Mailer',
'path' => 'vendor/swiftmailer/lib/classes/Swift/Mailer',
'arguments' => array('%swift.transport%'),
'shared' => TRUE,
),
),
),
);
您还可以使用程序化API创建容器。
// Creation Code
$container = new Dependency_Container(Dependency_Definition_List::factory()
->add('session', Dependency_Definition::factory()
->set_class('Session')
->set_constructor('instance')
->add_argument(new Dependency_Reference_Config('session.driver'))
->set_shared(TRUE)
)
->add('model', Dependency_Definition::factory()
->set_class('Model')
->set_constructor('factory')
)
->add('model.user', Dependency_Definition::factory()
->add_argument('user')
->add_method('set_session', array(new Dependency_Reference_Container('session')))
)
->add('swift.transport', Dependency_Definition::factory()
->set_class('Swift_SmtpTransport')
->set_path('vendor/swiftmailer/lib/classes/Swift/SmtpTransport')
->add_argument(new Dependency_Reference_Config('email.host'))
->add_argument(new Dependency_Reference_Config('email.port'))
->add_method('setEncryption', array(new Dependency_Reference_Config('email.encryption')))
)
->add('swift.mailer', Dependency_Definition::factory()
->set_class('Swift_Mailer')
->set_path('vendor/swiftmailer/lib/classes/Swift/Mailer')
->add_argument(new Dependency_Reference_Container('swift.transport'))
->set_shared(TRUE)
)
);
编译依赖容器
默认情况下,您通过服务路径访问依赖项。如果您愿意,可以编译一个容器类,该类将每个服务公开为类型提示方法。
换句话说
// You get this $services->get_swift_mailer()->send($message); // Instead of this $services->get('swift.mailer').send($message);
这提供了以下好处
- IDE自动完成可用的服务
- IDE自动完成和检测服务本身的方法的使用
- 清晰、可维护的定义,确定实际使用的接口实现,以便更容易调试
- 在编译时验证您的服务配置
使用提供的 compile:dependencies 小任务编译依赖项。在此任务期间,编译器将创建您的定义列表中的每个服务,如果任何服务无法实例化,则失败。
建议的使用方法是将此小任务放置在您的构建/部署任务中,以便每次部署时容器都重新编译,如果在依赖项中存在未检测到的破坏性更改,则早期失败。