適用:內容更新頻率低(分鐘/小時級)、版面固定、個性化需求少的頁面。
<?php
// render.php
function render_template(string $templatePath, array $data, string $outputPath): bool {
if (!is_file($templatePath)) {
throw new RuntimeException("Template not found: $templatePath");
}
// 提取變數至當前符號表
extract($data, EXTR_SKIP);
// 捕獲輸出緩衝
ob_start();
include $templatePath;
$html = ob_get_clean();
// 原子性寫入:寫暫存檔 -> rename
$tmpPath = $outputPath . '.tmp.' . bin2hex(random_bytes(4));
if (file_put_contents($tmpPath, $html) === false) {
return false;
}
if (!@rename($tmpPath, $outputPath)) {
@unlink($tmpPath);
return false;
}
// 可選:設定檔案權限
chmod($outputPath, 0644);
return true;
}
// 使用範例
$data = [
'title' => '最新文章',
'articles' => [
['id' => 1, 'title' => 'PHP 8.3 新特性', 'url' => '/article/1'],
['id' => 2, 'title' => '效能調優實戰', 'url' => '/article/2'],
],
'site_name' => '技術部落格',
];
render_template(__DIR__ . '/templates/list.php', $data, __DIR__ . '/public/articles/index.html');
模板檔 templates/list.php:
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<title><?= htmlspecialchars($title) ?> - <?= htmlspecialchars($site_name) ?></title>
<meta charset="UTF-8">
</head>
<body>
<h1><?= htmlspecialchars($title) ?></h1>
<ul>
<?php foreach ($articles as $art): ?>
<li><a href="<?= htmlspecialchars($art['url']) ?>"><?= htmlspecialchars($art['title']) ?></a></li>
<?php endforeach; ?>
</ul>
</body>
</html>
優點:繼承/區塊、自動轉義、沙箱安全、快取編譯、擴充函數/過濾器。
<?php
// 使用 Twig (composer require twig/twig)
require __DIR__ . '/vendor/autoload.php';
$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
$twig = new \Twig\Environment($loader, [
'cache' => __DIR__ . '/var/cache/twig',
'auto_reload' => true,
'strict_variables' => true,
'autoescape' => 'html',
]);
$html = $twig->render('list.twig', $data);
file_put_contents(__DIR__ . '/public/articles/index.html', $html);
Twig 模板 templates/list.twig:
{% extends 'base.twig' %}
{% block content %}
<h1>{{ title }}</h1>
<ul>
{% for article in articles %}
<li><a href="{{ article.url }}">{{ article.title }}</li>
{% endfor %}
</ul>
{% endblock %}
| 觸發方式 | 實現 | 優點 | 缺點 |
|---|---|---|---|
| 發布/更新內容後同步生成 | 應用層事件監聽器/觀察者 | 即時、簡單 | 阻塞回應、併發衝突 |
| 佇列非同步生成 | Redis/RabbitMQ + Worker 消費 | 解耦、可重試、平滑尖峰 | 延遲秒級、需監控佇列 |
| 定時掃描脏標記 | Cron 每分鐘掃描 `needs_regenerate=1` | 可控、批次處理 | 延遲分鐘級 |
| 靜態站點生成器 (SSG) | 構建階段一次性生成所有頁面 | 極致效能、版本控管 | 動態資料難整合、構建時間長 |
PHP 靜態頁面生成是「以空間換時間、以構建換運行」的經典策略。選擇原生 PHP 模板輕量快速,或Twig/Blade功能強大,配合佇列非同步與原子性寫入,構建高效能、高安全、易維護的內容交付系統。