从根本上说,依赖注入不是让对象创建一个依赖关系,也不是让工厂对象去创建对象,而是将所需的依赖变成一个外部对象,使之成为一个”某些人的问题”

你为”某些人的问题”注入了类的依赖关系。在laravel中,这个”某人”是 服务容器 。在laravel中,服务容器负责通过构造函数注入类的依赖关系。

任何时候,你在一个控制器类中请求一个依赖,这个服务容器负责:

  1. 自动地在构造函数中检测依赖关系
  2. 如果需要构建这个依赖关系
  3. 通过构造函数创建对象形成依赖关系

来看一个非常简单的例子。

 1 <?php
 2 namespace app\http\controllers;
 3 use app\user;
 4 use app\repositories\userrepository;
 5 use app\http\controllers\controller;
 6 class usercontroller extends controller
 7 {
 8     protected $userrepository;
 9     public function __construct(userrepository $userrepository)
10     {
11         $this->userrepository = $userrepository;
12     }
13     public function show($id)
14     {
15         $user = $this->userrepository->find($id);
16         return view('user.profile', ['user' => $user]);
17     }
18 }

 

假如,你有一个 usercontroller 类需要 userrepository 作为一个构造函数依赖。

  1. 服务容器使用 php 的 反射类 来检测,事实 userrepository 需要被优先解析。
  2. 然后,它构造 userrepository 实例。
  3. 然后,它构造 usercontroller 类实例。

依赖关系是如何被解析和注入的,我被很多 laravel 开发人员不知道这个简单而强大的技术感到迷惑。 这是一个非常强大的技术,它可以被用来解决复杂对象的依赖关系。

如果由于某种原因,您不希望laravel自动构建一个对象,您还可以通过传递一个可用于创建依赖关系的回调来告诉laravel service container如何构造该对象。

1 <?php
2 $container->bind('my\service', function($container) {
3   return new my\service($container->make('my\anotherservice'));
4 });

 

您需要创建一个服务提供商来注册上述服务。

 1 <?php
 2 namespace app\providers;
 3 use illuminate\support\serviceprovider;
 4 class myserviceprovider extends serviceprovider
 5 {
 6     public function register()
 7     {
 8         $this->app->singleton(\my\service::class, function ($app) {
 9             return new \my\service($app->make('my\anotherservice'));
10         });
11     }
12 }

 

当 my\service 需要被解析的时候,负责返回一个对象的回调函数就会被调用。

 1 <?php
 2 namespace app\http\controllers;
 3 use app\user;
 4 use app\http\controllers\controller;
 5 class mycontroller extends controller
 6 {
 7     protected $myservice;
 8     public function __construct(\my\service $myservice)
 9     {
10         $this->myservice = $myservice;
11     }
12     // .. 方法
13 }

 

真实的例子

假设你的应用需要facebook的php sdk来访问facebook的api,你的控制器就是这样的:

 1 <?php
 2 namespace app\http\controllers;
 3 use app\user;
 4 use app\http\controllers\controller;
 5 use facebook\facebook;
 6 class facebookapiaccesscontroller extends controller
 7 {
 8     protected $facebook;
 9     public function __construct(facebook\facebook $facebook)
10     {
11         $this->facebook = $facebook;
12     }
13     //.. action methods here
14 }

 

现在,您需要告诉service container如何构建 facebook\facebook的实例.

1 <?php
2 $container->singleton('facebook\facebook', function() {
3   return new \facebook\facebook([
4     'app_id' => config('services.facebook.app_id'),
5     'app_secret' => config('services.facebook.app_secret'),
6     'default_graph_version' => 'v2.10',
7   ]);
8 });

 

注意,我已经调用了方法singleton而不是bind。 唯一的区别是用singleton注册的服务被缓存,随后的解析服务调用返回缓存的服务。

结论

依赖注入是一种强大的技术,你可以在 laravel 中用来简化对象的创建. 默认情况下, laravel 的服务容器会自动的用反射去检测和解决依赖关系. 但是, 你可以指定回调来解析服务.