paginate返回的是think\paginator对象,非数组,故不能直接调用each();应先用items()获取当前页数据数组,再用array_map或foreach处理。

paginate 返回的是对象,不能直接用 each 处理数组
很多人写 $list = Db::name('user')->paginate(10)->each(...) 发现闭包没生效,或者报错 Call to undefined method think\Paginator::each()。这是因为 paginate() 返回的是 think\Paginator 实例,不是 PHP 数组,它没有 each() 方法。
真正要加工的是分页结果里的数据集合(即当前页的那几条记录),不是 Paginator 本身。
- 正确做法:先取
$list->items()得到当前页数据数组,再对它调用array_map或foreach - 错误写法:
$list->each(...)(Paginator 没这个方法)或Db::name(...)->select()->paginate(...)(先查全表再分页,性能灾难) - 如果硬要用链式风格,可封装成辅助函数,但别强求
each出现在 Paginator 后面
用 items() + array_map 做字段格式化最稳妥
$list->items() 返回的是当前页的纯 PHP 数组,每项是关联数组,适合做二次处理。比如时间戳转日期、HTML 实体解码、拼接 URL 等。
示例:对文章列表做创建时间格式化和描述解码
$list = Db::name('article')
->where('status', 'normal')
->paginate(10);
$items = array_map(function($item) {
$item['create_time'] = date('Y-m-d', (int)$item['create_time']);
$item['description'] = htmlspecialchars_decode($item['description'] ?? '');
return $item;
}, $list->items());
// 注意:此时 $items 是加工后的数组,$list 仍是 Paginator 实例
// 模板中仍用 {$list->render()} 输出分页 HTML
// 数据循环改用加工后的 $items,而不是 $list
- 别在闭包里修改
$item后不return,array_map 依赖返回值 - 时间字段务必强制转
(int),避免某些版本返回字符串导致date()报错 -
htmlspecialchars_decode()要判空,防止null或缺失字段触发警告
想保持 Paginator 接口统一?继承并重写 toArray()
如果你希望模板里仍能用 {$list->items} 直接拿到加工后数据(即让 items 属性自动带格式化逻辑),可以继承 think\Paginator,重写 toArray() 或添加访问器。
但注意:TP6 默认不鼓励继承 Paginator,更推荐“取出来加工”这种显式方式。真要定制,建议只覆盖 items() 方法:
class FormattedPaginator extends \think\Paginator
{
public function items()
{
return array_map(function($item) {
$item['create_time'] = date('Y-m-d', $item['create_time'] ?? 0);
$item['title'] = mb_substr($item['title'] ?? '', 0, 20, 'utf-8') . '...';
return $item;
}, parent::items());
}
}
- 这样控制器里仍可写
new FormattedPaginator(...),但需手动构造,失去paginate()链式便利 - 多数项目没必要走这步,
array_map+ 显式赋值更易调试、更少隐式行为 - 一旦重写
items(),要注意不要破坏分页元信息(如total()、hasPages())的准确性
分页链接参数丢失?appends() 别漏 request()->except(['page'])
加工数据本身不影响分页链接,但很多人顺手加搜索条件后发现翻页时 keyword 消失了——这不是二次处理的问题,而是 appends() 没配对。
常见错误是只写 $list->appends(['keyword' => $keyword]),但没把原始请求里其他参数(比如 category_id、sort)一起带上。
- 推荐写法:
$list->appends(request()->except(['page'])),干净且兼容空值 - 避免
request()->only(['keyword', 'category_id']),万一某个参数没传,URL 就多出?keyword=&category_id= - 如果参数来自 POST 表单,需在控制器里先收集再合并:
$list->appends(array_merge($searchData, request()->except(['page'])))
二次处理本身不碰 URL 构造逻辑,但常和分页一起出现,所以参数保留这事得同步检查——否则加工再漂亮,点下一页就回到默认状态。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











