什么是 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 表现与领域表现分离
使用场景指南
想把数据转数组以便复用
实现 Arrayable,把规范化逻辑集中在 toArray()。
想控制 JSON 表达
实现 Jsonable,用 toJson($options) 明确输出格式。
想作为 HTML 片段处理
实现 Htmlable,用 toHtml() 返回渲染字符串。
想直接返回 HTTP 响应
实现 Responsable,把职责集中到 toResponse($request)。
接下来阅读
Macroable trait 学习向既有类添加自定义方法的扩展模式。
Conditionable trait 学习用 when() / unless() 组织条件分支的设计。
tap() 辅助函数 / Tappable 学习插入副作用同时返回值的链式设计。
Dumpable trait 学习把 dump() / dd() 集成到对象中的调试方法。