TP8模板中{volist}遍历数组最稳妥,需控制器assign('list', $array)赋值,name与变量名一致,id定义项变量,关联数组须预处理为数字索引,嵌套时注意子项判空。

ThinkPHP8.0模板中用{volist}遍历数组最稳妥
直接在模板里写{volist name="list" id="item"}就能循环输出,这是TP8官方推荐、兼容性最好、且支持键值对和嵌套的语法。别用{foreach}——它虽能用,但不是TP原生标签,部分扩展或缓存场景下可能失效。
常见错误是把PHP数组直接传进模板却没检查结构:比如传的是$data['list'],模板却写{volist name="data" id="item"},结果报Undefined variable: data或者空渲染。
- 控制器必须用
$this->assign('list', $array)明确赋值,变量名要和name属性一致 -
id定义的是当前项变量名,可在循环体内用{$item.id}或{$item.name}取值 - 如果数组是关联索引(如
['a' => 1, 'b' => 2]),{volist}默认按数值索引处理,需先用array_values()转为数字索引,或改用{foreach}(但要接受非原生支持风险)
控制器传数组时注意assign()的键名和类型
TP8不自动展开多维数组,传二维数组时,如果字段含null或空字符串,{volist}不会报错但可能跳过该条——这不是bug,是模板引擎的静默过滤逻辑。
典型场景:查数据库后用toArray()得到$list,直接assign('list', $list)即可;但如果手动构造数组,比如$list = [['name'=>'张三'], ['name'=>null]],第二条在模板里{$item.name}会输出空白,而非null字面量。
立即学习“PHP免费学习笔记(深入)”;
- 确保数据已过滤:用
array_filter($list, 'is_array')剔除非法项 - 避免传引用或闭包:TP模板无法序列化它们,会导致
Serialization of closure is not allowed - 大数据量时慎用
limit+offset在模板里做分页,应由控制器完成分页查询再传$list
{volist}里访问键名要用key而不是index
index是从1开始的循环序号,key才是原始数组的键(仅当传入的是关联数组且你提前做了array_keys()映射才有效)。多数人混淆这两者,导致想取ID字段时误写{$item.index},结果输出1、2、3而不是真实ID。
正确做法:如果原始数组是['1001'=>['name'=>'A'],'1002'=>['name'=>'B']],模板中要显示ID,得在控制器里加一层键映射:
$list = array_map(function($v, $k) {
return ['id' => $k] + $v;
}, $rawData, array_keys($rawData));
$this->assign('list', $list);
然后模板写{$item.id}。硬要在{volist}里取原始键?不行——它不暴露key给id变量,只能靠预处理。
嵌套{volist}容易漏掉empty提示和层级缩进
比如商品列表带规格数组,外层{volist name="goods" id="g"},内层{volist name="g.specs" id="s"},一旦$g['specs']是null或空数组,内层直接不渲染,也不会触发{empty}——因为{volist}只对name指向的变量判空,不递归检测子项。
- 控制器中统一初始化:
$g['specs'] = $g['specs'] ?: [] - 嵌套时建议用
{notempty name="g.specs"}包裹内层{volist},比依赖{volist}...{empty}...{/volist}更可靠 - 模板缩进别靠空格“模拟层级”,用
<div class="indent">之类CSS控制,否则HTML结构混乱影响调试
assign()传了什么、{volist name=""}写了什么、{$item.xxx}能不能真正取到——这三处对齐了,90%的遍历问题就解决了。



















