Skip to content

IoC 容器

介绍

Laravel 的控制反转(IoC)容器是一个强大的工具,用于管理类依赖关系。依赖注入是一种消除硬编码类依赖关系的方法。相反,依赖关系在运行时被注入,从而允许更大的灵活性,因为依赖实现可以轻松地进行交换。

理解 Laravel IoC 容器对于构建强大且大型的应用程序以及为 Laravel 核心做出贡献至关重要。

基本用法

将类型绑定到容器中

IoC 容器可以通过闭包回调或自动解析来解析依赖关系。首先,我们将探索闭包回调。首先,可以将“类型”绑定到容器中:

php
App::bind('foo', function($app)
{
	return new FooBar;
});

从容器中解析类型

php
$value = App::make('foo');

当调用 App::make 方法时,闭包回调会被执行,并返回结果。

将“共享”类型绑定到容器中

有时,您可能希望将某个内容绑定到容器中,该内容只应解析一次,并且在后续调用中应返回相同的实例:

php
App::singleton('foo', function()
{
	return new FooBar;
});

将现有实例绑定到容器中

您还可以使用 instance 方法将现有对象实例绑定到容器中:

php
$foo = new Foo;

App::instance('foo', $foo);

在哪里注册绑定

IoC 绑定,如事件处理程序或路由过滤器,通常属于“引导代码”的范畴。换句话说,它们准备您的应用程序以实际处理请求,并且通常需要在实际调用路由或控制器之前执行。与大多数其他引导代码一样,start 文件始终是注册 IoC 绑定的一个选项。或者,您可以创建一个 app/ioc.php(文件名无关紧要)文件,并从您的 start 文件中要求该文件。

如果您的应用程序有大量的 IoC 绑定,或者您只是希望按类别将 IoC 绑定组织到单独的文件中,您可以在 服务提供者 中注册您的绑定。

自动解析

解析类

IoC 容器足够强大,可以在许多情况下无需任何配置即可解析类。例如:

php
class FooBar {

	public function __construct(Baz $baz)
	{
		$this->baz = $baz;
	}

}

$fooBar = App::make('FooBar');

请注意,即使我们没有在容器中注册 FooBar 类,容器仍然能够解析该类,甚至自动注入 Baz 依赖关系!

当类型未在容器中绑定时,它将使用 PHP 的反射功能来检查类并读取构造函数的类型提示。使用这些信息,容器可以自动构建类的实例。

将接口绑定到实现

然而,在某些情况下,一个类可能依赖于接口实现,而不是“具体类型”。在这种情况下,必须使用 App::bind 方法来告知容器要注入哪个接口实现:

php
App::bind('UserRepositoryInterface', 'DbUserRepository');

现在考虑以下控制器:

php
class UserController extends BaseController {

	public function __construct(UserRepositoryInterface $users)
	{
		$this->users = $users;
	}

}

由于我们已将 UserRepositoryInterface 绑定到具体类型,因此在创建此控制器时,DbUserRepository 将自动注入。

实际用法

Laravel 提供了几种机会来使用 IoC 容器,以增加应用程序的灵活性和可测试性。一个主要的例子是在解析控制器时。所有控制器都是通过 IoC 容器解析的,这意味着您可以在控制器构造函数中类型提示依赖关系,它们将自动被注入。

类型提示控制器依赖关系

php
class OrderController extends BaseController {

	public function __construct(OrderRepository $orders)
	{
		$this->orders = $orders;
	}

	public function getIndex()
	{
		$all = $this->orders->all();

		return View::make('orders', compact('all'));
	}

}

在这个例子中,OrderRepository 类将自动注入到控制器中。这意味着在 单元测试 中,可以将“模拟” OrderRepository 绑定到容器并注入到控制器中,从而允许轻松地模拟数据库层交互。

IoC 使用的其他示例

过滤器组合器事件处理程序 也可以从 IoC 容器中解析。当注册它们时,只需给出应使用的类的名称:

php
Route::filter('foo', 'FooFilter');

View::composer('foo', 'FooComposer');

Event::listen('foo', 'FooHandler');

服务提供者

服务提供者是将相关 IoC 注册分组到一个位置的好方法。可以将它们视为引导应用程序中组件的一种方式。在服务提供者中,您可以注册自定义身份验证驱动程序、将应用程序的存储库类注册到 IoC 容器中,甚至设置自定义 Artisan 命令。

实际上,大多数核心 Laravel 组件都包括服务提供者。您应用程序中注册的所有服务提供者都列在 app/config/app.php 配置文件的 providers 数组中。

定义服务提供者

要创建服务提供者,只需扩展 Illuminate\Support\ServiceProvider 类并定义 register 方法:

php
use Illuminate\Support\ServiceProvider;

class FooServiceProvider extends ServiceProvider {

	public function register()
	{
		$this->app->bind('foo', function()
		{
			return new Foo;
		});
	}

}

请注意,在 register 方法中,应用程序 IoC 容器可以通过 $this->app 属性访问。一旦您创建了提供者并准备好将其注册到应用程序中,只需将其添加到 app 配置文件中的 providers 数组中。

在运行时注册服务提供者

您还可以使用 App::register 方法在运行时注册服务提供者:

php
App::register('FooServiceProvider');

容器事件

注册解析监听器

每次容器解析对象时,都会触发一个事件。您可以使用 resolving 方法监听此事件:

php
App::resolvingAny(function($object)
{
	//
});

App::resolving('foo', function($foo)
{
	//
});

请注意,解析的对象将被传递给回调。