> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Contracts（契约）

> 介绍 Laravel Contracts 的作用、与门面的区别、通过类型提示注入的方式，以及自定义 Contract 的创建方法。

## 什么是 Contract

Laravel 的「Contracts」是一组定义框架核心服务的接口。例如，`Illuminate\Contracts\Queue\Queue` Contract 定义了队列所需的方法，`Illuminate\Contracts\Mail\Mailer` Contract 定义了发送邮件所需的方法。

每个 Contract 都有一个由框架提供的对应实现。例如，Laravel 提供了各种驱动的队列实现，以及基于 [Symfony Mailer](https://symfony.com/doc/current/mailer.html) 的邮件实现。

所有 Laravel Contract 都存放在[专门的 GitHub 仓库](https://github.com/illuminate/contracts)中。这既是所有可用 Contract 的快速参考，也是一份可以在构建与 Laravel 服务对接的包时单独使用的、隔离的包。

<Info>
  Contract 只是接口，其运行机制与 PHP 接口完全一致。Laravel 提供了这些接口的实现，并通过服务容器注入。
</Info>

## Contract 与 Facade 的区别

[门面](/zh/facades)和辅助函数提供了一种使用 Laravel 服务的便捷方式，而不需要在服务容器中通过类型提示解析 Contract。多数情况下，每个门面都有对应的 Contract。

门面与 Contract 的主要区别如下：

| 维度    | 门面                        | Contract         |
| ----- | ------------------------- | ---------------- |
| 依赖声明  | 不需要（任何位置都可以调用）            | 在构造器中显式声明        |
| 测试    | 通过 `shouldReceive()` mock | 通过标准的 mock 库替换实现 |
| 主要用途  | 应用内的便捷使用                  | 包开发、明确的依赖管理      |
| 代码可读性 | 只需一行导入                    | 构造器中的依赖一目了然      |

<Tip>
  门面不需要在类的构造器中声明，而 Contract 可以在构造器中作为显式依赖定义。有些开发者偏爱这种显式依赖的写法，因此使用 Contract。也有开发者喜欢门面带来的便利。**一般来说，大多数应用在开发过程中直接使用门面就足够了。**
</Tip>

## 什么时候使用 Contract

使用 Contract 还是门面主要看个人或团队的偏好。两者都能用来构建稳固、易测的 Laravel 应用。Contract 与门面并非互斥，你完全可以在应用的一部分使用门面，另一部分使用 Contract。

Contract 在下列场景中特别有用：

* **构建可与多个 PHP 框架集成的包时** — 使用 `illuminate/contracts` 包定义与 Laravel 服务的对接，就无需在 `composer.json` 中依赖 Laravel 的具体实现。
* **希望显式表达依赖时** — 只需查看构造器就能知道类依赖了什么。
* **需要替换实现时** — 通过服务容器可以轻松替换为其他实现。

## Contract 的使用方式

那么如何获取 Contract 的实现？其实非常简单。

Laravel 中许多类——控制器、事件监听器、中间件、队列任务、路由闭包等——都通过服务容器解析。因此获取 Contract 实现的方式，就是在被容器解析的类的构造器中对该接口进行「类型提示」。

```mermaid theme={null}
flowchart LR
    A["服务提供者<br>bind(Interface, Impl)"] --> B["服务容器<br>注册绑定"]
    C["构造器<br>类型提示：Interface"] --> B
    B --> D["自动注入<br>解析出 Interface 的实现"]
    D --> E["具体类的实例<br>可自由替换"]
```

例如以下事件监听器：

```php theme={null}
<?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，可以让应用组件之间的依赖关系更加清晰。

<Steps>
  <Step title="定义接口">
    在 `app/Contracts` 目录中创建接口。

    ```php theme={null}
    <?php

    namespace App\Contracts;

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

        /**
         * 退款
         */
        public function refund(string $transactionId): bool;
    }
    ```
  </Step>

  <Step title="创建实现类">
    创建实现该 Contract 的类。

    ```php theme={null}
    <?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;
        }
    }
    ```
  </Step>

  <Step title="在服务提供者中绑定">
    在[服务提供者](/zh/service-providers)中将 Contract 与实现绑定。

    ```php theme={null}
    use App\Contracts\PaymentGateway;
    use App\Services\StripePaymentGateway;

    $this->app->singleton(PaymentGateway::class, StripePaymentGateway::class);
    ```
  </Step>

  <Step title="通过类型提示接收注入">
    在控制器或其他类的构造器中进行类型提示。

    ```php theme={null}
    <?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
            );

            // ...
        }
    }
    ```
  </Step>
</Steps>

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

## 常用 Contract 一览

以下是常用 Contract 与其对应门面的对照表（部分）。

| Contract                                        | 对应门面                  |
| ----------------------------------------------- | --------------------- |
| `Illuminate\Contracts\Auth\Access\Gate`         | `Gate`                |
| `Illuminate\Contracts\Auth\Factory`             | `Auth`                |
| `Illuminate\Contracts\Bus\Dispatcher`           | `Bus`                 |
| `Illuminate\Contracts\Cache\Factory`            | `Cache`               |
| `Illuminate\Contracts\Cache\Repository`         | `Cache::driver()`     |
| `Illuminate\Contracts\Config\Repository`        | `Config`              |
| `Illuminate\Contracts\Console\Kernel`           | `Artisan`             |
| `Illuminate\Contracts\Container\Container`      | `App`                 |
| `Illuminate\Contracts\Encryption\Encrypter`     | `Crypt`               |
| `Illuminate\Contracts\Events\Dispatcher`        | `Event`               |
| `Illuminate\Contracts\Filesystem\Factory`       | `Storage`             |
| `Illuminate\Contracts\Filesystem\Filesystem`    | `Storage::disk()`     |
| `Illuminate\Contracts\Hashing\Hasher`           | `Hash`                |
| `Illuminate\Contracts\Mail\Mailer`              | `Mail`                |
| `Illuminate\Contracts\Notifications\Dispatcher` | `Notification`        |
| `Illuminate\Contracts\Queue\Factory`            | `Queue`               |
| `Illuminate\Contracts\Queue\Queue`              | `Queue::connection()` |
| `Illuminate\Contracts\Queue\ShouldQueue`        | —                     |
| `Illuminate\Contracts\Redis\Factory`            | `Redis`               |
| `Illuminate\Contracts\Routing\ResponseFactory`  | `Response`            |
| `Illuminate\Contracts\Routing\UrlGenerator`     | `URL`                 |
| `Illuminate\Contracts\Session\Session`          | `Session::driver()`   |
| `Illuminate\Contracts\Translation\Translator`   | `Lang`                |
| `Illuminate\Contracts\Validation\Factory`       | `Validator`           |
| `Illuminate\Contracts\View\Factory`             | `View`                |

完整 Contract 列表可在 [illuminate/contracts](https://github.com/illuminate/contracts) 仓库查看。

## 下一步

<Card title="门面" icon="layer-group" href="/zh/facades">
  了解门面的机制以及测试方式。
</Card>


## Related topics

- [创建 AI SDK 的自定义 Provider](/zh/advanced/ai-sdk-custom-provider.md)
- [Support Contracts（Arrayable / Jsonable / Htmlable / Responsable）](/zh/advanced/support-contracts.md)
- [Laravel 12 升级到 13 指南](/zh/blog/upgrade-12-to-13.md)
- [Laravel 10 升级到 11](/zh/blog/upgrade-10-to-11.md)
- [门面](/zh/facades.md)
