[转]smarty --foreach详解
Smarty 中的 {foreach} 是遍历数组的核心标签,相比仅支持数字索引数组的 {section},它语法更简洁、支持关联数组,是模板开发中高频使用的循环方式。本文将全面讲解 {foreach} 的语法、属性、核心特性及实战示例。
一、核心语法与属性说明
1. 基础语法
{foreach} 必须与 {/foreach} 成对出现,核心结构:
{foreach from=$数组变量 item=当前元素变量 [key=键名变量] [name=循环名称]}
// 循环体内容
{foreachelse}
// 数组为空时执行的内容
{/foreach}
2. 关键属性表
| 属性名(Attribute) | 类型(Type) | 是否必填(Required) | 默认值(Default) | 描述(Description) |
|---|---|---|---|---|
from | 数组(array) | 是(Yes) | n/a | 要循环遍历的目标数组 |
item | 字符串(string) | 是(Yes) | n/a | 循环中当前元素的变量名 |
key | 字符串(string) | 否(No) | n/a | 循环中当前元素的键名变量名(关联数组专用) |
name | 字符串(string) | 否(No) | n/a | 循环名称,用于访问循环的内置属性(如索引、次数) |
3. 核心规则
from和item是必填属性,缺一不可;name由字母、数字、下划线组成(同 PHP 变量命名规则),嵌套循环时名称必须唯一;from数组的长度决定循环次数;{foreachelse}仅在from数组为空时执行;name仅在需要访问循环内置属性时必填,未定义name时访问属性会导致不可预知结果(无报错)。
二、 {foreach} 内置属性
通过 {$smarty.foreach.循环名称.属性名} 访问,核心属性如下:
| 属性名 | 说明 |
|---|---|
index | 当前循环索引,从 0 开始递增 |
iteration | 当前循环次数,从 1 开始递增(与 index 唯一区别) |
first | 布尔值,当前是否为第一次循环(仅第一次为 TRUE) |
last | 布尔值,当前是否为最后一次循环(仅最后一次为 TRUE) |
show | 布尔值,控制循环是否显示(作为 {foreach} 参数使用,show=FALSE 时循环不渲染) |
total | 循环总次数(可在循环内/循环后使用) |
三、实战示例
示例 1:基础数字索引数组遍历
PHP 赋值:
<?php
$arr = [1000, 1001, 1002];
$smarty->assign('myArray', $arr);
?>
Smarty 模板:
<ul>
{foreach from=$myArray item=foo}
<li>{$foo}</li>
{/foreach}
</ul>
输出结果:
<ul>
<li>1000</li>
<li>1001</li>
<li>1002</li>
</ul>
示例 2:关联数组遍历(key + item)
PHP 赋值:
<?php
$arr = [9 => 'Tennis', 3 => 'Swimming', 8 => 'Coding'];
$smarty->assign('myArray', $arr);
?>
Smarty 模板:
<ul>
{foreach from=$myArray key=k item=v}
<li>{$k}: {$v}</li>
{/foreach}
</ul>
输出结果:
<ul>
<li>9: Tennis</li>
<li>3: Swimming</li>
<li>8: Coding</li>
</ul>
示例 3:多维关联数组遍历
PHP 赋值:
<?php
$items_list = [
23 => ['no' => 2456, 'label' => 'Salad'],
96 => ['no' => 4889, 'label' => 'Cream']
];
$smarty->assign('items', $items_list);
?>
Smarty 模板:
<ul>
{foreach from=$items key=myId item=i}
<li><a href="item.php?id={$myId}">{$i.no}: {$i.label}</a></li>
{/foreach}
</ul>
输出结果:
<ul>
<li><a href="item.php?id=23">2456: Salad</a></li>
<li><a href="item.php?id=96">4889: Cream</a></li>
</ul>
示例 4:嵌套循环
PHP 赋值:
<?php
$smarty->assign('contacts', [
['phone' => '1', 'fax' => '2', 'cell' => '3'],
['phone' => '555-4444', 'fax' => '555-3333', 'cell' => '760-1234']
]);
?>
Smarty 模板:
{foreach name=outer item=contact from=$contacts}
<hr />
{foreach key=key item=item from=$contact}
{$key}: {$item}<br /><br />
{/foreach}
{/foreach}
输出结果:
<hr />
phone: 1<br /><br />
fax: 2<br /><br />
cell: 3<br /><br />
<hr />
phone: 555-4444<br /><br />
fax: 555-3333<br /><br />
cell: 760-1234<br /><br />
示例 5: {foreachelse} 空数组处理
PHP 赋值:
<?php
// 模拟数据库查询无结果
$results = [];
$smarty->assign('results', $results);
?>
Smarty 模板:
{foreach key=cid item=con from=$results}
<a href="contact.php?contact_id={$cid}">{$con.name} - {$con.nick}</a><br /><br />
{foreachelse}
No items were found in the search
{/foreach}
输出结果:
No items were found in the search
示例 6:内置属性实战
6.1 index(每5行输出表头)
<table>
{foreach from=$items key=myId item=i name=foo}
{if $smarty.foreach.foo.index % 5 == 0}
<tr><th>Title</th></tr>
{/if}
<tr><td>{$i.label}</td></tr>
{/foreach}
</table>
6.2 index + iteration 对比
{foreach from=$myArray item=i name=foo}
{$smarty.foreach.foo.index}|{$smarty.foreach.foo.iteration},
{/foreach}
// 输出:0|1, 1|2, 2|3, ...
6.3 first(第一个元素标为LATEST)
<table>
{foreach from=$items key=myId item=i name=foo}
<tr>
<td>{if $smarty.foreach.foo.first}LATEST{else}{$myId}{/if}</td>
<td>{$i.label}</td>
</tr>
{/foreach}
</table>
6.4 last(最后一个元素加分割线)
{foreach from=$items key=part_id item=prod name=products}
<a href="#{$part_id}">{$prod}</a>{if $smarty.foreach.products.last}<hr>{else},{/if}
{foreachelse}
... content ...
{/foreach}
6.5 total(显示总条数)
{foreach from=$items key=part_id item=prod name=foo}
{$prod.name}<hr/>
{if $smarty.foreach.foo.last}
<div id="total">{$smarty.foreach.foo.total} items</div>
{/if}
{foreachelse}
... something else ...
{/foreach}
四、注意事项
- 嵌套循环命名:嵌套的
{foreach}必须设置不同的name,否则内置属性会冲突; - 空值处理:优先使用
{foreachelse}处理空数组,而非模板内判断count($数组); - 性能优化:遍历超大数组时,建议在 PHP 层预处理数据(如分页),避免模板内复杂逻辑;
- 属性访问:仅在需要使用
index/iteration/first/last/total时设置name,减少不必要的开销; - 与 {section} 区别:
{foreach}仅支持单个数组、语法简单;{section}支持更复杂的循环控制(如步长、偏移),但仅支持数字索引数组。
五、总结
{foreach} 是 Smarty 模板中最常用的循环标签,核心优势是支持关联数组、语法简洁、内置属性丰富。掌握其 from/item/key/name 属性及 index/iteration/first/last/total 内置属性,可覆盖绝大多数数组遍历场景。开发中优先使用 {foreach} 而非 {section},仅在需要复杂数字索引控制时才考虑 {section}。