ThinkPHP分页对象不能直接json_encode,因其是对象而非数组,直接编码会触发__toString()返回HTML;应调用toArray()获取标准分页数组,或items()->toArray()(TP6.3+可用all())获取纯数据。

ThinkPHP分页对象为什么不能直接 json_encode?
因为 think\Paginator(或 think\paginator\driver\Bootstrap 等具体驱动类)不是纯数组,它是个对象,内部封装了数据、分页信息和渲染逻辑。直接 json_encode 会触发其魔术方法 __toString(),结果是 HTML 字符串,不是你想要的结构化数据。
用 toArray() 方法获取基础分页数据
这是最常用也最安全的方式,toArray() 会返回一个包含 data(当前页记录)、current_page、last_page、per_page、total 等字段的标准数组:
$list = Db::name('user')->paginate(10);
$data = $list->toArray(); // ✅ 返回数组,可直接 json_encode
注意:toArray() 不包含 HTML 渲染字段(如 render),也不包含原始查询条件或模型实例,只保留分页元信息和当前页数据。
需要带分页链接(如 API 分页导航)怎么办?
原生 toArray() 不提供 next_page_url 或 prev_page_url 这类链接字段。如果你在 API 场景下需要这些,得手动拼接:
立即学习“PHP免费学习笔记(深入)”;
- 检查是否启用了
withQuery:分页对象默认不携带 URL 查询参数,需显式调用$list->appends(request()->param())再调用toArray(),否则render()生成的链接才带参数,但toArray()仍不会包含它们 - 若需
first_page_url等字段,建议自己构造:'first_page_url' => url('index') . '?page=1',并确保过滤掉敏感参数(如token) - TP6.1+ 支持
simple()分页,它返回更轻量的数组,但同样不含链接字段——链接必须由业务层按需生成
常见踩坑点:items() 和 all() 的区别
这两个方法都返回当前页数据,但行为不同:
-
$list->items():返回当前页的模型集合(Collection对象),需再调用toArray()才能转为二维数组 -
$list->all():仅 TP6.3+ 支持,等价于$list->items()->toArray(),直接返回数组 - 错误写法:
json_encode($list->items())→ 输出的是 Collection 对象的 JSON(含额外元数据),不是干净的数据列表
所以,要取纯数据数组,优先用 $list->items()->toArray() 或 TP6.3+ 的 $list->all(),而不是直接对 items() 结果做 json_encode。
真正麻烦的不是转换本身,而是分页对象里哪些字段该暴露、哪些该过滤——尤其是当分页结果要进 API 响应时,render、appends、path 这些字段既无用又可能泄露路径结构,得主动剔除或重定义输出结构。



















