ThinkPHP 6 的 json() 方法不能直接在控制器中调用,因其是响应类方法而非控制器内置函数;需用 return json($data) 或封装 ApiResult 工具类统一处理状态码、序列化异常及分页/模型兼容性。

ThinkPHP 6 的 json() 方法为什么不能直接用在所有场景
因为 json() 是响应类方法,不是控制器基类的内置函数;直接在控制器里写 $this->json($data) 会报错,除非你手动继承 think\Response 或调用 response()->json()。更麻烦的是,它不自动包裹状态码、消息、时间戳这些 API 常见字段。
常见错误现象:Call to undefined method app\controller\User::json() —— 这说明你误把响应构造逻辑当成了控制器方法。
- 真正能用的快捷方式是
return json($data)(TP6),但每次都要手写['code' => 0, 'msg' => 'ok', 'data' => $data],重复又易错 - 如果项目里混用
return $this->success()和return json(...),前端解析逻辑会混乱 -
json()默认不处理对象序列化失败(比如模型里有闭包或资源句柄),容易触发Exception: Object of class ... could not be converted to string
封装一个 ApiResult 工具类,绕过控制器继承限制
不用改控制器基类,也不用每个控制器都 use 一堆响应类;工具类静态方法 + 全局函数封装最轻量,且兼容 TP6.0 ~ TP6.3。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在
app/common/tool/ApiResult.php放工具类,namespace app\common\tool; - 提供
success()、fail()、error()三个静态方法,参数统一为$data = []、$msg = ''、$code = 0 - 内部一律用
response()->json([...])构造,避免依赖控制器上下文 - 关键点:对
$data做json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)预检,捕获异常后 fallback 到空数组并记录日志
示例:
return ApiResult::success(['id' => 123], '获取成功');输出:
{"code":0,"msg":"获取成功","data":{"id":123},"time":1718234567}
如何让 ApiResult 自动兼容分页和模型对象
TP6 的 Paginator 对象不能直接 json_encode,模型对象默认转成数组时可能带隐藏属性或关联数据,直接塞进 data 会出问题。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 遇到
Paginator实例,先调用$paginator->toArray(),再提取['data' => ..., 'per_page' => ..., 'total' => ...]结构 - 遇到
Model实例,强制走$model->toArray(),避免魔术方法或访问器干扰(比如某些字段被hidden但你其实需要) - 不要在工具类里自动调用
visible()或append()—— 这属于业务逻辑,应由控制器显式传入已处理好的数组 - 性能影响:每次调用
toArray()会触发一次属性遍历,大数据量分页时注意用withAttr控制字段,别在ApiResult里做转换
全局异常处理器里怎么复用 ApiResult
TP6 默认的 app\common\exception\Handle.php 里,render() 方法返回的是 Response 对象,但你不能直接 return ApiResult::error(...),因为它是 Response 实例,而 render() 要求返回 Response 或字符串。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 修改
render(),检测是否是 API 请求(比如通过请求头X-Requested-With: XMLHttpRequest或路由前缀/api/) - 是 API 请求时,用
response()->json(...)构造,否则走默认 HTML 渲染 - 关键点:别在
render()里调ApiResult::error(),它内部已经调了一次response(),嵌套会导致响应头重复发送 - 推荐做法:抽一个
buildApiError($e)私有方法,只负责组装数组,再交给response()->json()
容易被忽略的地方:异常堆栈信息绝对不能直接返回给前端,ApiResult 的 error() 方法里要过滤掉 $e->getTraceAsString(),只留 $e->getMessage() 和自定义错误码。



















