图片 5

Laravel学习教程之IOC容器的介绍与用例

从容器中取得一个类型

Laravel核心概念

$foo = new Foo;

App::instance('foo', $foo);

0x03 契约(Contracts)

图片 1

Laravel Contract

App::register('FooServiceProvider');

下一步

Laravel 作为“为 Web 艺术家创造的 PHP
框架”,接下来我将学习其中最重要的内容之一 HTTP
层的相关知识。同样会整理成思维导图的形式以方便记忆与回顾。

这些文章都将首发在微信公众号:up2048
上。欢迎大家扫描下面的二维码,我们一起学习,分享,讨论,反思。

思维导图导出为图片时会导致其变模糊。若需要高清的思维导图源文件,请关注微信公众号:up2048,并回复“精进脑图”来获取。

– EOF –

运行时注册服务提供器

如何从服务容器解析出对象?

绑定后可以从服务容器中解析出对象才能够使用。解析方法包括:

  • 通过 make 方法,接收一个你想要解析的类或者接口
  • 通过数组方式从容器中解析对象
  • 自动注入

服务器提供器是将一组相关 IoC
注册到单一路径的有效方法。将它们看做是一种引导组件的方法。在服务器提供器里,你可以注册自定义的验证驱动器,使用
IoC 容器注册应用程序仓库类,甚至是自定义 Artisan 命令。

0x00 服务容器

Laravel 的核心就是一个 IoC
容器,该容器提供了整个框架中需要的一系列服务。

IoC(Inversion Of
Control)控制反转
,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。IoC
容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数参数中去。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。这就是依赖注入(Dependency
Injection,
DI)
。依赖注入实质上是指:类的依赖通过构造器或在某些情况下通过「setter」方法进行「注入」。

图片 2

Laravel服务容器

现在考虑下这个控制器:

Facades
为应用程序的服务容器中可用的类提供了一个「静态」接口。它实际上是服务容器中那些底层类的「静态代理」。

自动解析

0x02 门面(Facades)

图片 3

Laravel Facade

Laravel使用IoC(Inversion of
Control,控制倒转,这是一个设计模式,可以先查看下百科)容器这个强有力的工具管理类依赖。依赖注入(也是一种设计模式,一般用于实现IoC)是一个不用编写固定代码来处理类之间依赖的方法,相反的,这些依赖是在运行时注入的,这样允许处理依赖时具有更大的灵活性。

如何使用契约?

Laravel 中的许多类型的类都是通过 服务容器
解析出来的。包括控制器、事件监听器、中间件、任务队列,甚至路由的闭包。所以说,要获得一个契约的实现,你只需要解析在类的构造函数中相应的类型约束即可。

例如,看看这个事件监听器,当事件监听器被解析时,服务容器会从构造函数里读取到类型约束,并注入对应的值。

<?php

namespace App\Listeners;

use App\User;
use App\Events\OrderWasPlaced;
use Illuminate\Contracts\Redis\Database;

class CacheOrderInformation
{
    /**
     * Redis 数据库实现。
     */
    protected $redis;

    /**
     * 创建事件处理器实例。
     *
     * @param  Database  $redis
     * @return void
     */
    public function __construct(Database $redis)
    {
        $this->redis = $redis;
    }

    /**
     * 处理事件。
     *
     * @param  OrderWasPlaced  $event
     * @return void
     */
    public function handle(OrderWasPlaced $event)
    {
        //
    }
}
class UserController extends BaseController {

 public function __construct(UserRepositoryInterface $users)
 {
  $this->users = $users;
 }

}

服务提供者则提供服务并绑定服务至服务容器。是所有 Laravel
应用程序引导启动的中心所在。

IoC绑定,很像事件句柄或者路由过滤,通常在”bootstrap
code(引导代码)”之后完成。换句话说,它们在你的应用程序准备处理请求,也即是在一个路由或者控制器被实际执行之前执行。和其他引导代码一样,start文件通常作为IoC绑定注册一种方法。另外,你可以创建一个app/ioc.php(文件名不一定一样)文件,并在start文件中包含它。

Laravel 的 契约(Contracts )是一系列框架用来定义核心服务的接口。

注意:在 register
方法,应用程序通过 $this->app 属性访问 IoC
容器。一旦你已经创建了提供器并且想将它注册到应用程序中, 只需简单的放入
app 配置文件里 providers 数组中。

Facades 工作原理

在 Laravel 应用中,一个 facade
就是一个提供访问容器中对象的类。其中核心的部件就是 Facade 类。不管是
Laravel 自带的 Facades ,还是用户自定义的 Facades ,都继承自
Illuminate\Support\Facades\Facade 类。

Facade 基类使用 __callStatic() 魔术方法在你的 Facades
中延迟调用容器中对应对象的方法,在下面的例子中,调用了 Laravel
的缓存系统。在代码里,我们可能认为是 Cache 类中的静态方法 get 被调用了:

<?php
namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * 显示给定用户的大体信息。
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        $user = Cache::get('user:'.$id);

        return view('profile', ['user' => $user]);
    }
}

注意在代码的最上面,我们导入的是 Cache facade 。这个 facade
其实是我们获取底层 Illuminate\Contracts\Cache\Factory
接口实现的一个代理。我们通过这个 facade 调用的任何方法,都会被传递到
Laravel 缓存服务的底层实例中。

如果我们看一下 Illuminate\Support\Facades\Cache
这个类,你会发现类中根本没有 get 这个静态方法:

class Cache extends Facade
{
    /**
     * 获取组件在容器中注册的名称。
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}

其实,Cache facade 是继承了 Facade 基类,并且定义了 getFacadeAccessor()
方法。这个方法的作用是返回服务容器中对应名字的绑定内容。当用户调用 Cache
facade 中的任何静态方法时, Laravel 会解析到服务容器中绑定的键值为 cache
实例对象,并调用这个对象对应的方法(在这个例子中就是 get 方法)。

如果你的应用程序有很大量IoC绑定,或者你想根据不同的分类将IoC绑定分割到不同的文件,你可以尝试在服务提供器(见下面)中进行绑定

自动注入实例

下面的例子中,在控制器的构造函数中对应用程序定义的 Repository
使用类型提示。这样 Repository 实例会被自动解析并注入到类中:

<?php

namespace App\Http\Controllers;

use App\Users\Repository as UserRepository;

class UserController extends Controller
{
    /**
     * user repository 实例。
     */
    protected $users;

    /**
     * 控制器构造方法。
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

    /**
     * 显示指定 ID 的用户信息。
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        //
    }
}

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

图片 4

你也可以使用 App::register 方法在运行时注册服务提供器:

服务容器是 Laravel 的核心,是一个 IoC
容器,是管理类依赖和运行依赖注入的有力工具。

绑定一个”共享“类型到容器

Laravel
的核心概念包括:服务容器、服务提供者、门面(Facades)、契约(Contracts)。

事实上,大多数核心 Laravel
组件包含服务提供器。应用程序所有注册在服务提供器的均列在 
app/config/app.php 配置文件的 providers 数组中。

0x01 服务提供者

Laravel 中,包括应用程序,以及所有的 Laravel
核心服务,都是通过服务提供者引导启动的。所谓的「引导启动」指的是注册事务,包括注册服务容器绑定,事件监听器,中间件,甚至路由。

图片 5

Laravel服务提供者

所有服务提供者都需要继承 Illuminate\Support\ServiceProvider
类。大多数服务提供者都包含 register 和 boot 方法。register
方法中,只能将事务绑定到 服务容器。不应该在 register
方法中尝试注册任何事件监听器,路由或者任何其他功能。可以为服务提供者的
boot 方法设置类型提示。服务容器会自动注入需要的任何依赖。boot
方法将在所有其他服务提供者均已注册之后调用。

所有服务提供者都在 config/app.php
配置文件中注册。可以选择推迟服务提供者的注册,直到真正需要注册绑定时,这样可以提供应用程序的性能。

绑定一个接口实现

推荐阅读

App::resolvingAny(function($object)
{
 //
});

App::resolving('foo', function($foo)
{
 //
});

不管是契约还是门面都可以创建出强大的、容易测试的 Laravel 应用程序。

绑定一个已经存在的类型实例到容器

如何实现与服务容器的绑定?

几乎所有服务容器的绑定都是在服务提供者中进行的。在服务提供者内部,可以通过
$this->app 来访问容器的实例。

绑定的方式包括:

  • 简单绑定
  • 绑定一个单例
  • 绑定实例
  • 绑定接口到实现
  • 情境绑定
  • 绑定包括原始数据在内的初始数据
  • 标记

其中,标记能够针对某种类别的所有做绑定。

定义服务提供器

App::bind('foo', function($app)
{
 return new FooBar;
});

服务提供器

您可能感兴趣的文章:

由于我们将 UserRepositoryInterface 绑定了具体类,DbUserRepository
在该控制器创建时将会被自动注入到该控制器。

use Illuminate\Support\ServiceProvider;

class FooServiceProvider extends ServiceProvider {

 public function register()
 {
  $this->app->bind('foo', function()
  {
   return new Foo;
  });
 }

}

注意:获取到的对象将会传入回调函数中。

class FooBar {

 public function __construct(Baz $baz)
 {
  $this->baz = $baz;
 }

}

$fooBar = App::make('FooBar');
App::singleton('foo', function()
{
 return new FooBar;
});

注意:我们虽然没有在容器中注册FooBar类,容器仍然可以取得该类,甚至自动注入Baz依赖!

总结

理解 Laravel IoC容器是构建强大应用程序所必要的,也有助于Laravel
核心本身。下面话不多说了,来一起看看详细的介绍吧。

前言

IoC容器足够强大,在许多场景下不需要任何配置就能取得类。例如

然而,在某些情况下,一个类可能依赖某个接口实现,而不是一个
“具体的类”。当在这种情况下,App::bind方法必须通知容器注入哪个接口实现:

$value = App::make('foo');

IoC
容器有两种方法来解决依赖关系:通过闭包回调或者自动解析。首先,我们来探究一下闭包回调。首先,需要绑定一个“类型”到容器中:

容器事件

当执行 App::make 方法,闭包函数被执行并返回结果。

取得一个类

注册获取事件监听者

在这个例子中,OrderRepository 将会自动注入到控制器。意味着当 单元测试
模拟请求时,OrderRepository
将会绑定到容器以及注入到控制器中,允许无痛与数据库层交互。

哪里去注册绑定呢

要创建服务提供器,只需继承 Illuminate\Support\ServiceProvider
类并且定义一个 register 方法:

Route::filter('foo', 'FooFilter');

View::composer('foo', 'FooComposer');

Event::listen('foo', 'FooHandler');

实际用例

当某个类型没有绑定到容器,IoC容器将使用 PHP
的反射工具来检查类和读取构造器的类型提示。使用这些信息,容器可以自动构建类实例。

过滤器, composers, 和
事件句柄也能够从IoC容器中获取到。当注册它们的时候,只需要把它们使用的类名简单给出即可:

你也可以使用instance方法,将一个已经存在的对象接口绑定到容器中:

译者:mpandar(马胜盼)

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'));
 }

}

容器在每次获取对象时都触发一个事件。你可以通过使用 resolving
方法来监听该事件:

对控制器的依赖关系做类型提示

有时,你只想将绑定到容器的类型处理一次,然后接下来从容器中取得的都应该是相同实例:

App::bind('UserRepositoryInterface', 'DbUserRepository');

绑定一个类型到容器

基本用例

IoC 使用的其他例子

Laravel 提供了几个方法使用 IoC
容器增强应用程序可扩展性和可测试性。一个主要的例子是取得控制器。所有控制器都通过
IoC
容器取得,意味着可以在控制器构造方法中对依赖的类型提示,它们将自动被注入。