[转]smarty --foreach详解

ChenReal

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. 核心规则

  • fromitem 是必填属性,缺一不可;
  • 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}

四、注意事项

  1. 嵌套循环命名:嵌套的 {foreach} 必须设置不同的 name,否则内置属性会冲突;
  2. 空值处理:优先使用 {foreachelse} 处理空数组,而非模板内判断 count($数组)
  3. 性能优化:遍历超大数组时,建议在 PHP 层预处理数据(如分页),避免模板内复杂逻辑;
  4. 属性访问:仅在需要使用 index/iteration/first/last/total 时设置 name,减少不必要的开销;
  5. 与 {section} 区别{foreach} 仅支持单个数组、语法简单;{section} 支持更复杂的循环控制(如步长、偏移),但仅支持数字索引数组。

五、总结

{foreach} 是 Smarty 模板中最常用的循环标签,核心优势是支持关联数组、语法简洁、内置属性丰富。掌握其 from/item/key/name 属性及 index/iteration/first/last/total 内置属性,可覆盖绝大多数数组遍历场景。开发中优先使用 {foreach} 而非 {section},仅在需要复杂数字索引控制时才考虑 {section}