跳转到主要内容

什么是 Support Contracts

Illuminate\Contracts\Support 汇集了 Laravel 全局中体量虽小但很重要的接口。 其中 Arrayable / Jsonable / Htmlable / Responsable 是让 Value Object、DTO、Response 对象自然融入 Laravel 现有流程的基本模式。
这里的签名来自 Laravel 13.x 的官方源代码(laravel/framework)。

1) Arrayable

接口定义

interface Arrayable
{
    public function toArray();
}

实现示例

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

接口定义

interface Jsonable
{
    public function toJson($options = 0);
}

实现示例

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

接口定义

interface Htmlable
{
    public function toHtml();
}

实现示例

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 !!} 的场景中,也便于用对象管理输出
在实现 Htmlable 的类内部,不要直接拼接用户输入。必要的值请先用 e() 转义再嵌入。

4) Responsable

接口定义

interface Responsable
{
    public function toResponse($request);
}

实现示例

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 表现与领域表现分离

使用场景指南

1

想把数据转数组以便复用

实现 Arrayable,把规范化逻辑集中在 toArray()
2

想控制 JSON 表达

实现 Jsonable,用 toJson($options) 明确输出格式。
3

想作为 HTML 片段处理

实现 Htmlable,用 toHtml() 返回渲染字符串。
4

想直接返回 HTTP 响应

实现 Responsable,把职责集中到 toResponse($request)

接下来阅读

Macroable trait

学习向既有类添加自定义方法的扩展模式。

Conditionable trait

学习用 when() / unless() 组织条件分支的设计。

tap() 辅助函数 / Tappable

学习插入副作用同时返回值的链式设计。

Dumpable trait

学习把 dump() / dd() 集成到对象中的调试方法。
最后修改于 2026年7月13日