IoC 容器
介绍
Laravel 的控制反转(IoC)容器是一个强大的工具,用于管理类依赖关系。依赖注入是一种消除硬编码类依赖关系的方法。相反,依赖关系在运行时被注入,从而允许更大的灵活性,因为依赖实现可以轻松地进行交换。
理解 Laravel IoC 容器对于构建强大且大型的应用程序以及为 Laravel 核心做出贡献至关重要。
基本用法
将类型绑定到容器中
IoC 容器可以通过闭包回调或自动解析来解析依赖关系。首先,我们将探索闭包回调。首先,可以将“类型”绑定到容器中:
App::bind('foo', function($app)
{
return new FooBar;
});
从容器中解析类型
$value = App::make('foo');
当调用 App::make
方法时,闭包回调会被执行,并返回结果。
将“共享”类型绑定到容器中
有时,您可能希望将某个内容绑定到容器中,该内容只应解析一次,并且在后续调用中应返回相同的实例:
App::singleton('foo', function()
{
return new FooBar;
});
将现有实例绑定到容器中
您还可以使用 instance
方法将现有对象实例绑定到容器中:
$foo = new Foo;
App::instance('foo', $foo);
在哪里注册绑定
IoC 绑定,如事件处理程序或路由过滤器,通常属于“引导代码”的范畴。换句话说,它们准备您的应用程序以实际处理请求,并且通常需要在实际调用路由或控制器之前执行。与大多数其他引导代码一样,start
文件始终是注册 IoC 绑定的一个选项。或者,您可以创建一个 app/ioc.php
(文件名无关紧要)文件,并从您的 start
文件中要求该文件。
如果您的应用程序有大量的 IoC 绑定,或者您只是希望按类别将 IoC 绑定组织到单独的文件中,您可以在 服务提供者 中注册您的绑定。
自动解析
解析类
IoC 容器足够强大,可以在许多情况下无需任何配置即可解析类。例如:
class FooBar {
public function __construct(Baz $baz)
{
$this->baz = $baz;
}
}
$fooBar = App::make('FooBar');
请注意,即使我们没有在容器中注册 FooBar 类,容器仍然能够解析该类,甚至自动注入 Baz
依赖关系!
当类型未在容器中绑定时,它将使用 PHP 的反射功能来检查类并读取构造函数的类型提示。使用这些信息,容器可以自动构建类的实例。
将接口绑定到实现
然而,在某些情况下,一个类可能依赖于接口实现,而不是“具体类型”。在这种情况下,必须使用 App::bind
方法来告知容器要注入哪个接口实现:
App::bind('UserRepositoryInterface', 'DbUserRepository');
现在考虑以下控制器:
class UserController extends BaseController {
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
}
由于我们已将 UserRepositoryInterface
绑定到具体类型,因此在创建此控制器时,DbUserRepository
将自动注入。
实际用法
Laravel 提供了几种机会来使用 IoC 容器,以增加应用程序的灵活性和可测试性。一个主要的例子是在解析控制器时。所有控制器都是通过 IoC 容器解析的,这意味着您可以在控制器构造函数中类型提示依赖关系,它们将自动被注入。
类型提示控制器依赖关系
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 容器中解析。当注册它们时,只需给出应使用的类的名称:
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
方法:
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
方法在运行时注册服务提供者:
App::register('FooServiceProvider');
容器事件
注册解析监听器
每次容器解析对象时,都会触发一个事件。您可以使用 resolving
方法监听此事件:
App::resolvingAny(function($object)
{
//
});
App::resolving('foo', function($foo)
{
//
});
请注意,解析的对象将被传递给回调。