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

# Support Contracts（Arrayable / Jsonable / Htmlable / Responsable）

> 基于 Laravel 13 官方源码，讲解 Illuminate\Contracts\Support 中 4 个主要契约。

## 什么是 Support Contracts

`Illuminate\Contracts\Support` 汇集了 Laravel 全局中体量虽小但很重要的接口。
其中 `Arrayable` / `Jsonable` / `Htmlable` / `Responsable` 是让 Value Object、DTO、Response 对象自然融入 Laravel 现有流程的基本模式。

```mermaid theme={null}
flowchart TD
    A["Value Object / DTO"] --> B["Arrayable<br>toArray()"]
    A --> C["Jsonable<br>toJson($options = 0)"]
    A --> D["Htmlable<br>toHtml()"]
    A --> E["Responsable<br>toResponse($request)"]
    B --> F["JsonResponse / Eloquent / Collection"]
    C --> F
    D --> G["e() helper / Blade output"]
    E --> H["Controller return / Router::toResponse()"]
```

<Info>
  这里的签名来自 Laravel 13.x 的官方源代码（`laravel/framework`）。
</Info>

## 1) Arrayable

### 接口定义

```php theme={null}
interface Arrayable
{
    public function toArray();
}
```

### 实现示例

```php theme={null}
use Illuminate\Contracts\Support\Arrayable;

final class Money implements Arrayable
{
    public function __construct(
        public readonly int $amount,
        public readonly string $currency,
    ) {}

    public function toArray(): array
    {
        return [
            'amount' => $this->amount,
            'currency' => $this->currency,
        ];
    }
}
```

### 在 Laravel 核心中的使用

* `Illuminate\Database\Eloquent\Model` 实现了 `Arrayable`，提供 `toArray()`
* `Illuminate\Http\JsonResponse::setData()` 检测到 `Arrayable` 时会用 `json_encode($data->toArray(), ...)` 序列化

### 包开发中的应用要点

* 让 DTO、Value Object 在 Controller、Resource、日志输出中拥有统一格式
* 将「转数组」的职责封装在对象自身

## 2) Jsonable

### 接口定义

```php theme={null}
interface Jsonable
{
    public function toJson($options = 0);
}
```

### 实现示例

```php theme={null}
use Illuminate\Contracts\Support\Jsonable;

final class ApiPayload implements Jsonable
{
    public function __construct(
        private array $data,
    ) {}

    public function toJson($options = 0): string
    {
        return json_encode([
            'data' => $this->data,
            'generated_at' => now()->toIso8601String(),
        ], $options | JSON_THROW_ON_ERROR);
    }
}
```

### 在 Laravel 核心中的使用

* `Model` 同时实现了 `Jsonable`，提供 `toJson($options = 0)`
* `JsonResponse::setData()` 会优先判定 `Jsonable`，使用其 `toJson()`

### 包开发中的应用要点

* 在审计日志、Webhook 发送中严格固定 JSON 结构
* 不完全依赖 `json_encode()`，把领域相关的 JSON 表达明确写在对象里

## 3) Htmlable

### 接口定义

```php theme={null}
interface Htmlable
{
    public function toHtml();
}
```

### 实现示例

```php theme={null}
use Illuminate\Contracts\Support\Htmlable;

final class BadgeHtml implements Htmlable
{
    public function __construct(
        private string $label,
    ) {}

    public function toHtml(): string
    {
        $escaped = e($this->label);

        return "<span class=\"badge\">{$escaped}</span>";
    }
}
```

### 在 Laravel 核心中的使用

* `Illuminate\Support\HtmlString` 实现了 `Htmlable`
* `e()` 辅助函数在参数是 `Htmlable` 时会返回其 `toHtml()`（不再转义）

### 包开发中的应用要点

* 明确在 Blade 中安全传递 HTML 片段的职责边界
* 使用 `{!! $obj !!}` 的场景中，也便于用对象管理输出

<Tip>
  在实现 `Htmlable` 的类内部，不要直接拼接用户输入。必要的值请先用 `e()` 转义再嵌入。
</Tip>

## 4) Responsable

### 接口定义

```php theme={null}
interface Responsable
{
    public function toResponse($request);
}
```

### 实现示例

```php theme={null}
use Illuminate\Contracts\Support\Responsable;

final class ExportCsvResponse implements Responsable
{
    public function __construct(
        private array $rows,
        private string $filename = 'export.csv',
    ) {}

    /**
     * @param \Illuminate\Http\Request $request
     */
    public function toResponse($request)
    {
        return response()->streamDownload(function () {
            $stream = fopen('php://output', 'w');

            foreach ($this->rows as $row) {
                fputcsv($stream, $row);
            }

            fclose($stream);
        }, $this->filename, [
            'Content-Type' => 'text/csv',
        ]);
    }
}
```

### 在 Laravel 核心中的使用

* `Illuminate\Routing\Router::toResponse()` 会先判定 `Responsable`，调用 `$response->toResponse($request)`
* `Illuminate\Http\Resources\Json\JsonResource` 实现了 `Responsable`，Controller 中可以直接 `return UserResource::make($user);`

### 包开发中的应用要点

* Controller 不再手动组数组，可以把响应生成委托给对象
* 更容易做「DTO 原样 return」的设计，将 HTTP 表现与领域表现分离

## 使用场景指南

<Steps>
  <Step title="想把数据转数组以便复用">
    实现 `Arrayable`，把规范化逻辑集中在 `toArray()`。
  </Step>

  <Step title="想控制 JSON 表达">
    实现 `Jsonable`，用 `toJson($options)` 明确输出格式。
  </Step>

  <Step title="想作为 HTML 片段处理">
    实现 `Htmlable`，用 `toHtml()` 返回渲染字符串。
  </Step>

  <Step title="想直接返回 HTTP 响应">
    实现 `Responsable`，把职责集中到 `toResponse($request)`。
  </Step>
</Steps>

## 接下来阅读

<Columns cols={2}>
  <Card title="Macroable trait" icon="puzzle-piece" href="/zh/advanced/macroable">
    学习向既有类添加自定义方法的扩展模式。
  </Card>

  <Card title="Conditionable trait" icon="git-branch" href="/zh/advanced/conditionable">
    学习用 `when()` / `unless()` 组织条件分支的设计。
  </Card>

  <Card title="tap() 辅助函数 / Tappable" icon="hand-point-up" href="/zh/advanced/tap">
    学习插入副作用同时返回值的链式设计。
  </Card>

  <Card title="Dumpable trait" icon="bug" href="/zh/advanced/dumpable">
    学习把 `dump()` / `dd()` 集成到对象中的调试方法。
  </Card>
</Columns>


## Related topics

- [Laravel Boost](/zh/boost.md)
- [Contracts（契约）](/zh/contracts.md)
- [延迟 Service Provider](/zh/advanced/deferred-provider.md)
- [辅助函数](/zh/helpers.md)
- [门面](/zh/facades.md)
