依赖注入
依赖注入是个花俏的名词,事实上是指:类的依赖通过构造器或在某些情况下通过「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)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
当有了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();