[ Laravel 5.3 文档 ] 核心概念 —— 契约(Contracts)

1、简介

Laravel中的契约是指框架提供的一系列定义核心服务的接口。 例如 ,Illuminate\Contracts\Queue\Queue契约定义了队列任务需要实现的方法,Illuminate\Contracts\Mail\Mailer契约定义了发送邮件所需要实现的方法。

每一个契约都有框架提供的相应实现。例如,Laravel为队列提供了多个驱动的实现,邮件则由 SwiftMailer驱动 实现 。

所有Laravel契约都有其对应的GitHub库,这为所有有效的契约提供了快速入门指南,同时也可以作为独立、解耦的包被包开发者使用。

契约(Contracts) VS 门面(Facades)

Laravel门面为Laravel服务的使用提供了便捷方式——不再需要从服务容器中类型提示和契约 解析即可直接通过静态门面调用 。有些开发者喜欢这种便捷,不过也有开发者倾向于使用契约,他们喜欢定义明确的依赖。

注:大多数应用中,不管你使用门面还是契约,合适就好。不过,如果你是在构建一个扩展包,那么就应该使用契约,因为这在扩展包中更容易测试。

2、何时使用契约

正如上面所讨论的,大多数情况下使用契约还是门面取决于个人或团队的喜好,契约和门面都可以用于创建强大的、测试友好的Laravel应用。只要你保持类的职责单一,你会发现使用契约和门面并没有什么实质性的差别。

但是,对契约你可能还是有些疑问。例如,为什么要全部使用接口?使用接口是不是更复杂?下面让我们从两个方面来扒一扒为什么使用接口:松耦合和简单。

松耦合

首先,让我们看看一些缓存实现的紧耦合代码:

<?php

namespace App\Orders;

class Repository{
    /**
     * 缓存
     */
    protected $cache;

    /**
     * 创建一个新的Repository实例
     *
     * @param  \SomePackage\Cache\Memcached  $cache
     * @return void
     */
    public function __construct(\SomePackage\Cache\Memcached $cache)
    {
        $this->cache = $cache;
    }

    /**
     * 通过ID获取订单
     *
     * @param  int  $id
     * @return Order
     */
    public function find($id)
    {
        if ($this->cache->has($id))    {
            //
        }
    }
}

在这个类中,代码和给定缓存实现紧密耦合,由于我们基于一个来自包的具体的缓存类,如果包的API变了,那么相应的,我们的代码必须做修改。

类似的,如果我们想要替换底层的缓存技术(Memcached)为别的技术实现(Redis),我们将再一次不得不修改我们的代码库。我们的代码库应该并不知道谁提供的数据或者数据是怎么提供的。

我们可以基于一种简单的、与提供者无关的接口来优化我们的代码,从而替代上述那种实现:

<?php

namespace App\Orders;

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository{
    /**
     * 创建一个新的Repository实例
     *
     * @param  Cache  $cache
     * @return void
     */
    public function __construct(Cache $cache)
    {
        $this->cache = $cache;
    }
}

现在代码就不与任何特定提供者耦合,甚至与Laravel都是无关的。由于契约包不包含任何实现和依赖,你可以轻松的为给定契约编写可选实现代码,你可以随意替换缓存实现而不用去修改任何缓存消费代码。

简单

当所有Laravel服务都统一在简单接口中定义,很容易判断给定服务提供的功能。契约可以充当框架特性的简明文档

此外,基于简单接口,代码也更容易理解和维护。在一个庞大而复杂的类中,与其追踪哪些方法是有效的,不如转向简单、干净的接口。

3、如何使用契约

那么,如何实现契约呢?这很简单。

Laravel中很多类都是通过服务容器进行解析,包括控制器,以及监听器、中间件、队列任务,甚至路由闭包。所以,要实现一个契约,需要在解析类的构造函数中类型提示这个契约接口。

例如,看看下面这个事件监听器:

<?php

namespace App\Listeners;

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

class CacheOrderInformation
{
    /**
     * The Redis database implementation.
     */
    protected $redis;

    /**
     * Create a new event handler instance.
     *
     * @param  Database  $redis
     * @return void
     */
    public function __construct(Database $redis)
    {
        $this->redis = $redis;
    }

    /**
     * Handle the event.
     *
     * @param  OrderWasPlaced  $event
     * @return void
     */
    public function handle(OrderWasPlaced $event)
    {
        //
    }
}

事件监听器被解析的时候,服务容器会读取构造函数中的类型提示,并注入适当的值。要学习更多关于服务容器的注册细节,参考其文档。

4、契约列表

下面是Laravel契约列表,以及其对应的“门面”:

Contract References Facade
Illuminate\Contracts\Auth\Factory Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Broadcasting\Broadcaster
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache::driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Queue\Factory Queue::driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View

学院君

学院君 has written 548 articles

资深PHP工程师,Laravel学院院长