通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

为什么我们需要Laravel IoC容器

因为Laravel 哲学的一个重要组成部分就是 IoC 容器,也可以称为服务容器。它是一个 Laravel 应用的核心部分,因此理解并使用 IoC 容器是我们必须掌握的一项重要技能。IoC 容器是一个非常强大的类管理工具。它可以自动解析类。

一、为什么我们需要Laravel IoC容器

因为Laravel 哲学的一个重要组成部分就是 IoC 容器,也可以称为服务容器。它是一个 Laravel 应用的核心部分,因此理解并使用 IoC 容器是我们必须掌握的一项重要技能。IoC 容器是一个非常强大的类管理工具。它可以自动解析类。

首先,我想先谈下依赖反转原则,对它的了解会有助于我们更好地理解 IoC 容器的重要性。

该原则规定:

高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。
抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。

一言以蔽之:依赖于抽象而非具体

class MySQLConnection

{

   /**

   * 数据库连接

   */

   public function connect()

   {

      var_dump(‘MYSQL Connection’);

   }

}

class PasswordReminder

{   

    /**

     * @var MySQLConnection

     */

     private $dbConnection;

    public function __construct(MySQLConnection $dbConnection)

    {

      $this->dbConnection = $dbConnection;

    }

}

大家常常会有一个误解,那就是依赖反转就只是依赖注入的另一种说法。但其实二者是不同的。在上面的代码示例中,尽管在 PasswordReminder 类中注入了 MySQLConnection 类,但它还是依赖于 MySQLConnection 类。

然而,高层次模块 PasswordReminder 是不应该依赖于低层次模块 MySQLConnection 的。

如果我们想要把 MySQLConnection 改成 MongoDBConnection,那我们就还得手动修改 PasswordReminder 类构造函数里的依赖。

PasswordReminder 类应该依赖于抽象接口,而非具体类。那我们要怎么做呢?请看下面的例子:

interface ConnectionInterface

{

   public function connect();

}

class DbConnection implements ConnectionInterface

{

 /**

  * 数据库连接

  */

 public function connect()

 {

   var_dump(‘MYSQL Connection’);

 }

}

class PasswordReminder

{

    /**

    * @var DBConnection

    */

    private $dbConnection;

    public function __construct(ConnectionInterface $dbConnection)

    {

      $this->dbConnection = $dbConnection;

    }

}

通过上面的代码,如果我们想把 MySQLConnection 改成 MongoDBConnection,根本不需要去修改 PasswordReminder 类构造函数里的依赖。因为现在 PasswordReminder 类依赖的是接口,而非具体类。

现在我要讲下 IoC 容器里到底发生了什么。我们可以把 IoC 容器简单地理解为就是一个容器,里面装的是类的依赖。

OrderRepositoryInterface 接口:

namespace App\Repositories;

interface OrderRepositoryInterface

{

   public function getAll();

}

DbOrderRepository 类:

namespace App\Repositories;

class DbOrderRepository implements OrderRepositoryInterface

{

  function getAll()

  {

    return ‘Getting all from mysql’;

  }

}

OrdersController 类:

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;

use App\Repositories\OrderRepositoryInterface;

class OrdersController extends Controller

{

    protected $order;

   function __construct(OrderRepositoryInterface $order)

   {

     $this->order = $order;

   }

   public function index()

   {

     dd($this->order->getAll());

     return View::make(orders.index);

   }

}

路由:

Route::resource(‘orders’, ‘OrdersController’);

现在,在浏览器中输入这个地址 <http://localhost:8000/orders>

报错了吧,错误的原因是服务容器正在尝试去实例化一个接口,而接口是不能被实例化的。解决这个问题,只需把接口绑定到一个具体的类上。

把下面这行代码加在路由文件里就搞定了:

App::bind(‘App\Repositories\OrderRepositoryInterface’, ‘App\Repositories\DbOrderRepository’)

延伸阅读:

二、控制反转和依赖注入是什么

控制反转,是指对象的创建和配置的控制权从调用方转移给容器。好比在家自己做菜,菜的味道全部由自己控制;去餐馆吃饭,菜的味道则是交由餐馆控制。IoC 容器就担任了餐馆的角色。

有了 IoC 容器,我们可以将对象交由容器管理,交由容器管理后的对象称之为 Bean。调用方不再负责组件的创建,要使用组件时直接获取 Bean 即可:

@Component

public class UserServiceImpl implements UserService{

    @Autowired // 获取 Bean

    private UserDao userDao;

}

调用方只需按照约定声明依赖项,所需要的 Bean 就自动配置完毕了,就好像在调用方外部注入了一个依赖项给其使用,所以这种方式称之为 依赖注入(Dependency Injection,缩写为 DI)。控制反转和依赖注入是一体两面,都是同一种开发模式的表现形式。

相关文章