Smarty 的 {foreach} 是模板中遍歷數組、對象集合的核心標籤。本文涵蓋模板寫法、編譯器解析邏輯、緩存生成、實際調用示例四大部分。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{$web_title}</title>
</head>
<body>
{$article_title}
<br/>
-- by {$author}
<hr/>
<br/>
{$content}
<br/>
-- publish @ {$time}
<br/><br/>
foreach test:
{foreach (from=url key=b item=c)}
<a href="index.php?article_id={$b}">{$c}</a>
{/foreach}
<br/>
</body>
</html>
<?php
// 1. 普通變量替換:{$var} -> var_tpl_arr["var"]; ?>
$pattern_var = "/\{$left_tag\}\$([\w\d]+)\{$right_tag\}/";
$replace_var = 'var_tpl_arr["$1"]; ?>';
if (preg_match($pattern_var, $content)) {
$content = preg_replace($pattern_var, $replace_var, $content);
}
// 2. 匹配 {foreach ...} 開始標籤
preg_match_all("/\{$left_tag}foreach\s+([^{]+?)\{$right_tag\}/is", $content, $match_foreach);
if (isset($match_foreach[1]) && is_array($match_foreach[1])) {
foreach ($match_foreach[1] as $match_key => $match_value) {
// 解析屬性:from=url key=b item=c
$split_foreachs = array_filter(preg_split('/\s+/is', $match_value));
$new_foreach_tag = array();
foreach ($split_foreachs as $split_foreach) {
$split = explode("=", $split_foreach);
if (count($split) == 2) {
if (in_array($split[0], array("from", "item", "key"))) {
$new_foreach_tag[$split[0]] = $split[1];
}
}
}
// 提取屬性
$from = $key = $item = '';
extract($new_foreach_tag);
// 構建 key 部分:$key => 或空
$key = ($key) ? '$' . $key . ' =>' : '';
// 生成 PHP foreach 代碼
$replace_foreach = 'var_tpl_arr["' . $from . '"] as ' . $key . ' $' . $item . ') { ?>';
$content = str_replace($match_foreach[0][$match_key], $replace_foreach, $content);
}
}
// 3. 處理 {/foreach} 閉合標籤
$pattern_foreach = "/\{$left_tag}\/foreach\{$right_tag\}/";
$replace_foreach = "";
if (preg_match($pattern_foreach, $content)) {
$content = preg_replace($pattern_foreach, $replace_foreach, $content);
}
// 4. 循環內變量:{==var} ->
// 注意:這裡使用雙 $ 實現變量變量($b、$c 為 foreach 產生的局部變量)
$pattern_var = "/\{$left_tag}==([\w\d]+)\{$right_tag\}/";
$replace_var = '';
if (preg_match($pattern_var, $content)) {
$content = preg_replace($pattern_var, $replace_var, $content);
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo $this->var_tpl_arr["web_title"]; ?></title>
</head>
<body>
<?php echo $this->var_tpl_arr["article_title"]; ?>
<br/>
-- by <?php echo $this->var_tpl_arr["author"]; ?>
<hr/>
<br/>
<?php echo $this->var_tpl_arr["content"]; ?>
<br/>
-- publish @ <?php echo $this->var_tpl_arr["time"]; ?>
<br/><br/>
foreach test:
<?php foreach($this->var_tpl_arr["url"] as $b => $c) { ?>
<a href="index.php?article_id=<?php echo $b; ?>"><?php echo $c; ?></a>
<?php } ?>
<br/>
</body>
</html>
<?php
require_once 'core/YATP.class.php';
$app = new YATP();
date_default_timezone_set("Asia/Shanghai");
$app->is_cache = false;
// 賦值變量
$article_title = "yet, it is a simple template engine";
$author = "sanwhiteyu@tencent.com";
$web_title = "just test";
$content = "It is easy to write a simple template engine for yourself, what u can do is try to do it!";
$time = date("Y-m-d H:i:s", time());
// 關鍵:傳入關聯數組供 foreach 遍歷
$url = array(
"url1" => "https://www.111cn.net",
"url2" => "https://www.baidu.com",
);
$app->assign("article_title", $article_title);
$app->assign("author", $author);
$app->assign("web_title", $web_title);
$app->assign("content", $content);
$app->assign("time", $time);
$app->assign("url", $url);
$app->display("index.html");
?>
| 特性 | 模板語法 | 編譯邏輯 | 注意點 |
|---|---|---|---|
| 數據源 | from=url | 映射到 $this->var_tpl_arr["url"] | 必須在 PHP 中 assign 同名變量 |
| 鍵名變量 | key=b | 生成 $b => | 可選,省略則無鍵名 |
| 值變量 | item=c | 生成 $c | 必填 |
| 循環內引用 | {==b} {==c} | 轉為 (變量變量) | 雙 $ 關鍵,區別於普通 {$var} |
| 嵌套循環 | 支援 | 遞歸編譯,變量作用域隔離 | 內層 item/key 勿與外層重名 |
{foreachelse} 標籤(Smarty 3+)或預判斷 {if $url|@count}templates_c/ 目錄或設置 $smarty->force_compile = true掌握 foreach 編譯機制,能更精準控制模板輸出,避免變量衝突與作用域陷阱。