ThinkPHP 6.0+ 的 paginate() 默认返回 Paginator 对象而非数组,字段名改为 per_page、current_page 等 Laravel 风格,total 为 int 类型,data 需用 items() 显式获取;适配旧接口应手动组装 TP5 风格数组,避免直接 json($paginator) 或 toArray()。

ThinkPHP 6.0+ 的 paginate() 返回结构变了
老项目升级到 ThinkPHP 6.0 或更高版本后,前端突然收不到 data 字段,或者 total 变成字符串、last_page 消失——不是接口写错了,是 paginate() 默认返回格式从「数组」切到了「对象」,且字段命名和类型都调整了。
核心变化:不再自动调用 toArray(),也不再兼容 TP5 的扁平结构;默认返回的是 think\Paginator\Bootstrap(或对应驱动)实例,JSON 序列化时会走自定义 jsonSerialize() 方法,字段名变成 per_page、current_page、last_page 等 Laravel 风格命名。
- 如果你在控制器里直接
return $list->paginate(10),前端拿到的是带方法和元信息的对象结构,不是纯数据 - TP5 返回的
data字段,在 TP6+ 中对应的是data属性,但需显式提取;原始数据藏在$paginator->items()里 - 字段类型也变了:
total是 int,但last_page是 int,has_more是 bool —— 不再统一转字符串
如何快速适配旧接口(兼容 TP5 格式)
最省事的办法:不改前端,只在后端把分页结果“拍平”成 TP5 风格数组。关键就两步:取数据 + 手动组装。
- 用
$paginator->items()拿真实数据列表,别用$paginator->toArray()['data']—— TP6+ 的toArray()仍保留部分对象结构,不可靠 - 手动构建返回数组,字段名对齐旧版:
data、current_page、last_page、per_page、total、has_next_page(注意:TP5 没has_next_page,但前端常用来判断“还能不能加载”,建议加) - 避免直接
json($paginator),这会触发 Paginator 的 JSON 序列化逻辑,字段和类型都不受控
示例代码:
立即学习“PHP免费学习笔记(深入)”;
$paginator = User::where('status', 1)->paginate(10);
$data = $paginator->items();
return json([
'code' => 0,
'msg' => 'ok',
'data' => $data,
'current_page' => $paginator->currentPage(),
'last_page' => $paginator->lastPage(),
'per_page' => $paginator->listRows(),
'total' => $paginator->total(),
'has_next_page'=> $paginator->hasMore(),
]);
为什么不能直接用 toArray() 或 render()
toArray() 看起来最省事,但它在 TP6+ 中返回的是混合结构:外层是分页元信息,内层 data 才是列表 —— 但这个 data 本身还是对象(Collection),JSON 化后可能嵌套过深或丢失 key;而 render() 是生成 HTML 分页条的,完全不适用于 API 接口。
-
$paginator->toArray()在 TP6.3+ 中返回类似['data' => Collection, 'current_page' => 1, ...],Collection 不会自动转数组,前端解析会失败 - 有些团队在中间件里全局
json_encode,但没处理Collection类型,导致data字段变成空对象{} -
render()输出的是<li><a href="...">2</a></li>这种 HTML 字符串,API 接口返回它等于直接报错
升级后分页参数传参习惯也要同步改
TP6+ 默认页码参数名从 page 改成了 page(看起来没变),但实际底层读取逻辑变了:它现在依赖 Request 对象的 param() 而非 get(),且对参数过滤更严格。如果前端还传 ?page=2&limit=20,TP6+ 的 paginate(20) 会忽略 limit,只认 list_rows 配置或固定值。
- 页码参数名仍是
page,但必须确保没被中间件或路由规则拦截/重命名 - 每页条数不再支持 URL 传
limit,要改成分页方法的第二个参数,或统一配置'list_rows' => 15在config/paginate.php里 - 如果用了自定义查询(比如
Db::table(...)->paginate()),记得检查是否漏了->where()条件 —— TP6+ 的分页构造器对空查询更敏感,容易返回全表
事情说清了就结束。



















