TP8.0 推荐用 DTO 封装请求参数,通过类型安全校验、字段声明与规则内聚实现参数组织;支持自动绑定、嵌套结构、默认值与不可变性,控制器专注业务逻辑。

TP8.0 中处理大量请求参数,核心不是“怎么取”,而是“怎么组织”——用 DTO(Data Transfer Object)封装 + 类型安全校验,让参数从散乱的字符串变成结构清晰、可验证、可复用的对象。
DTO 是 TP8 的第一道参数防线
别再写 $id = $this->request->param('id/d') 一长串了。TP8 推荐为每个接口定义专属 DTO 类,它天然承载三件事:字段声明、类型约束、校验规则。
- DTO 类必须继承
think\Validate或使用validate目录下的独立验证器,但更推荐直接在 DTO 中定义规则(TP8 支持属性级注解或数组规则) - 利用 PHP 8.1+ 的只读属性 + 构造函数提升,保证数据不可变:
public function __construct(public readonly int $id, public readonly string $name) - 字段名与请求参数名保持一致,TP8 的
Request::validate()或validate()方法能自动绑定并校验
自动绑定 DTO,告别手动 param()
TP8 不再鼓励逐个调用 param(),而是通过依赖注入或显式验证完成批量绑定:
- 控制器方法中直接声明 DTO 类型提示:
public function create(UserCreateDTO $dto) - 框架会自动尝试从请求中提取参数,按字段名匹配,并触发 DTO 内部的验证逻辑
- 若验证失败,TP8 默认抛出
ValidateException,由全局异常处理器统一返回标准错误格式(如{"code":400,"msg":"用户名不能为空"}) - 支持 JSON、表单、路由变量混合解析,无需区分
get()或post()
嵌套结构与复杂类型,用 DTO 嵌套解决
遇到 user[profile][avatar] 或 JSON 数组提交?靠点号拼接 param('user.profile.avatar') 易错且不可维护。正确做法是:
- 在主 DTO 中声明嵌套 DTO 属性:
public readonly UserProfileDTO $profile - 为
UserProfileDTO单独定义字段和规则,TP8 会递归校验整个结构 - 前端传 JSON:
{"name":"张三","profile":{"avatar":"/a.jpg","bio":"..."}},后端自动映射为完整对象树 - 对数组字段(如
tags: ["a","b"]),DTO 属性声明为public readonly array $tags,配合array|string联合类型确保兼容性
安全与默认值,写在 DTO 构造里
空值、非法值、缺失字段——这些不该在控制器里做 ?? 或 empty() 判断。全部前移到 DTO 初始化阶段:
- 构造函数中设默认值:
public function __construct(public readonly string $status = 'draft') - 类型后缀逻辑移到 DTO 验证规则中,比如
'name' => 'require|alphaNum',比param('name/s')更明确、可测试 - 敏感字段(如密码)可加
readonly+private属性,仅允许构造时赋值,杜绝后续篡改 - 所有字段初始化即完成合法性检查,控制器拿到的就是“可信数据”,专注业务调度即可


















