跳转到主要内容

什么是 Contract

Laravel 的「Contracts」是一组定义框架核心服务的接口。例如,Illuminate\Contracts\Queue\Queue Contract 定义了队列所需的方法,Illuminate\Contracts\Mail\Mailer Contract 定义了发送邮件所需的方法。 每个 Contract 都有一个由框架提供的对应实现。例如,Laravel 提供了各种驱动的队列实现,以及基于 Symfony Mailer 的邮件实现。 所有 Laravel Contract 都存放在专门的 GitHub 仓库中。这既是所有可用 Contract 的快速参考,也是一份可以在构建与 Laravel 服务对接的包时单独使用的、隔离的包。
Contract 只是接口,其运行机制与 PHP 接口完全一致。Laravel 提供了这些接口的实现,并通过服务容器注入。

Contract 与 Facade 的区别

门面和辅助函数提供了一种使用 Laravel 服务的便捷方式,而不需要在服务容器中通过类型提示解析 Contract。多数情况下,每个门面都有对应的 Contract。 门面与 Contract 的主要区别如下:
维度门面Contract
依赖声明不需要(任何位置都可以调用)在构造器中显式声明
测试通过 shouldReceive() mock通过标准的 mock 库替换实现
主要用途应用内的便捷使用包开发、明确的依赖管理
代码可读性只需一行导入构造器中的依赖一目了然
门面不需要在类的构造器中声明,而 Contract 可以在构造器中作为显式依赖定义。有些开发者偏爱这种显式依赖的写法,因此使用 Contract。也有开发者喜欢门面带来的便利。一般来说,大多数应用在开发过程中直接使用门面就足够了。

什么时候使用 Contract

使用 Contract 还是门面主要看个人或团队的偏好。两者都能用来构建稳固、易测的 Laravel 应用。Contract 与门面并非互斥,你完全可以在应用的一部分使用门面,另一部分使用 Contract。 Contract 在下列场景中特别有用:
  • 构建可与多个 PHP 框架集成的包时 — 使用 illuminate/contracts 包定义与 Laravel 服务的对接,就无需在 composer.json 中依赖 Laravel 的具体实现。
  • 希望显式表达依赖时 — 只需查看构造器就能知道类依赖了什么。
  • 需要替换实现时 — 通过服务容器可以轻松替换为其他实现。

Contract 的使用方式

那么如何获取 Contract 的实现?其实非常简单。 Laravel 中许多类——控制器、事件监听器、中间件、队列任务、路由闭包等——都通过服务容器解析。因此获取 Contract 实现的方式,就是在被容器解析的类的构造器中对该接口进行「类型提示」。 例如以下事件监听器:
<?php

namespace App\Listeners;

use App\Events\OrderWasPlaced;
use App\Models\User;
use Illuminate\Contracts\Redis\Factory;

class CacheOrderInformation
{
    /**
     * 创建事件监听器
     */
    public function __construct(
        protected Factory $redis,
    ) {}

    /**
     * 处理事件
     */
    public function handle(OrderWasPlaced $event): void
    {
        // ...
    }
}
当事件监听器被解析时,服务容器会读取构造器上的类型提示并注入合适的实现。

创建自定义 Contract

通过创建自己的 Contract,可以让应用组件之间的依赖关系更加清晰。
1

定义接口

app/Contracts 目录中创建接口。
<?php

namespace App\Contracts;

interface PaymentGateway
{
    /**
     * 扣款指定金额
     */
    public function charge(int $amount, string $token): bool;

    /**
     * 退款
     */
    public function refund(string $transactionId): bool;
}
2

创建实现类

创建实现该 Contract 的类。
<?php

namespace App\Services;

use App\Contracts\PaymentGateway;

class StripePaymentGateway implements PaymentGateway
{
    public function charge(int $amount, string $token): bool
    {
        // 使用 Stripe API 进行扣款...
        return true;
    }

    public function refund(string $transactionId): bool
    {
        // 使用 Stripe API 进行退款...
        return true;
    }
}
3

在服务提供者中绑定

服务提供者中将 Contract 与实现绑定。
use App\Contracts\PaymentGateway;
use App\Services\StripePaymentGateway;

$this->app->singleton(PaymentGateway::class, StripePaymentGateway::class);
4

通过类型提示接收注入

在控制器或其他类的构造器中进行类型提示。
<?php

namespace App\Http\Controllers;

use App\Contracts\PaymentGateway;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    public function __construct(
        protected PaymentGateway $payment,
    ) {}

    public function store(Request $request)
    {
        $this->payment->charge(
            $request->amount,
            $request->payment_token
        );

        // ...
    }
}
采用这种模式后,即使把支付服务从 Stripe 换成其他供应商,只要修改一处绑定即可,控制器代码无需变动。

常用 Contract 一览

以下是常用 Contract 与其对应门面的对照表(部分)。
Contract对应门面
Illuminate\Contracts\Auth\Access\GateGate
Illuminate\Contracts\Auth\FactoryAuth
Illuminate\Contracts\Bus\DispatcherBus
Illuminate\Contracts\Cache\FactoryCache
Illuminate\Contracts\Cache\RepositoryCache::driver()
Illuminate\Contracts\Config\RepositoryConfig
Illuminate\Contracts\Console\KernelArtisan
Illuminate\Contracts\Container\ContainerApp
Illuminate\Contracts\Encryption\EncrypterCrypt
Illuminate\Contracts\Events\DispatcherEvent
Illuminate\Contracts\Filesystem\FactoryStorage
Illuminate\Contracts\Filesystem\FilesystemStorage::disk()
Illuminate\Contracts\Hashing\HasherHash
Illuminate\Contracts\Mail\MailerMail
Illuminate\Contracts\Notifications\DispatcherNotification
Illuminate\Contracts\Queue\FactoryQueue
Illuminate\Contracts\Queue\QueueQueue::connection()
Illuminate\Contracts\Queue\ShouldQueue
Illuminate\Contracts\Redis\FactoryRedis
Illuminate\Contracts\Routing\ResponseFactoryResponse
Illuminate\Contracts\Routing\UrlGeneratorURL
Illuminate\Contracts\Session\SessionSession::driver()
Illuminate\Contracts\Translation\TranslatorLang
Illuminate\Contracts\Validation\FactoryValidator
Illuminate\Contracts\View\FactoryView
完整 Contract 列表可在 illuminate/contracts 仓库查看。

下一步

门面

了解门面的机制以及测试方式。
最后修改于 2026年7月13日