zeelot/kohana-dependencies

此包已被废弃,不再维护。未建议替代包。

为Kohana 3.x提供的依赖注入容器模块

dev-0.7/develop / 0.7.x-dev 2015-06-17 19:31 UTC

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) 是一个用于管理依赖并简化依赖注入维护的组件。使用依赖注入的一些主要论据包括它

  • 简化单元测试和模拟(或使其成为可能)
  • 解耦对象实例化和使用
  • 允许更好地分离关注点并提高对象内聚度
  • 减少单例类的使用和需求,而单例类被许多人认为是不好的

有关依赖注入的信息,您应阅读以下文章

使用此依赖注入容器

容器有一个->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 小任务编译依赖项。在此任务期间,编译器将创建您的定义列表中的每个服务,如果任何服务无法实例化,则失败。

建议的使用方法是将此小任务放置在您的构建/部署任务中,以便每次部署时容器都重新编译,如果在依赖项中存在未检测到的破坏性更改,则早期失败。