依赖注入
依赖注入是个花俏的名词,事实上是指:类的依赖通过构造器或在某些情况下通过「setter」方法「注入」。先看一段 Laravel 控制器里的代码实例:
<?php namespace App\Http\Controllers; use Illuminate\Routing\Controller; use App\Users\Repository as UserRepository; class UserController extends Controller { /** * 用户 Repository 的实例。 */ protected $users; /** * 创建一个新的控制器实例。 * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 显示指定 ID 的用户。 * * @param int $id * @return View */ public function show($id) { $user_info = $this->users->find($id); return view('user', ['user_info' => $user_info]); } }
Laravel 通过服务容器来管理类依赖并进行依赖注入。如果使用一个接口作为函数参数的类型提示,这个时候就需要将指定的实现绑定到接口上面:
interface EventPusher { public function send($data); }
class RedisEventPusher implements EventPusher { public function send($data) { // } }
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
use App\Contracts\EventPusher; /** * 创建一个新的类实例。 * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher) { $this->pusher = $pusher; }
这个就是所谓的面向接口编程,接口可以理解为一个规范、一个约束。高层模块不直接依赖于低层模块,它们都应该依赖于抽象(指接口)。
使用依赖注入,最重要的一点好处就是有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
控制反转
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则。其中**最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
<?php /** * 没有IoC/DI的时候,常规的A类使用C类的示例 */ /** * Class c */ class c { public function say() { echo 'hello'; } } /** * Class a */ class a { private $c; public function __construct() { $this->c = new C(); // 实例化创建C类 } public function sayC() { echo $this->c->say(); // 调用C类中的方法 } } $a = new a(); $a->sayC();
当有了IoC/DI的容器后,A类不再主动去创建C了,如下图所示:
而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中,如下图所示:
<?php /** * 当有了IoC/DI的容器后,a类依赖c实例注入的示例 */ /** * Class c */ class c { public function say() { echo 'hello'; } } /** * Class a */ class a { private $c; public function setC(C $c) { $this->c = $c; // 实例化创建C类 } public function sayC() { echo $this->c->say(); // 调用C类中的方法 } } $c = new C(); $a = new a(); $a->setC($c); $a->sayC();