傳統 require 'header.php' 方式雖簡單,但難以向佈局文件傳遞動態參數(如頁面標題、當前導航高亮、SEO 標簽)。本文展示如何用 函數封裝 替代直接包含,實現佈局參數化、邏輯解耦、測試友好。
| 方式 | 傳參能力 | 作用域隔離 | 單元測試 | 代碼復用 |
|---|---|---|---|---|
require 'header.php' | 依賴全局變量 | 無(共享當前作用域) | 困難 | 低 |
printHeader($title) | 顯式參數列表 | 函數作用域隔離 | 易於 Mock | 高 |
layout.php<?php
/**
* 輸出頁面頭部
* @param string $title 頁面標題
* @param array $meta 額外 meta 標簽 ['keywords'=>..., 'description'=>...]
* @param string $activeNav 當前激活導航標識
*/
function printHeader(string $title, array $meta = [], string $activeNav = ''): void {
$defaultMeta = [
'charset' => 'UTF-8',
'viewport' => 'width=device-width, initial-scale=1',
'keywords' => '默認關鍵詞',
'description' => '默認描述',
];
$meta = array_merge($defaultMeta, $meta);
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="<?= $meta['charset'] ?>">
<meta name="viewport" content="<?= $meta['viewport'] ?>">
<meta name="keywords" content="<?= htmlspecialchars($meta['keywords']) ?>">
<meta name="description" content="<?= htmlspecialchars($meta['description']) ?>">
<title><?= htmlspecialchars($title) ?></title>
<link rel="stylesheet" href="/assets/css/app.css">
</head>
<body>
<header>
<nav>
<a href="/" class="<?= $activeNav==='home'?'active':'' ?>">首頁</a>
<a href="/about" class="<?= $activeNav==='about'?'active':'' ?>">關於</a>
<a href="/contact" class="<?= $activeNav==='contact'?'active':'' ?>">聯繫</a>
</nav>
</header>
<main>
<?php
}
/**
* 輸出頁面尾部
*/
function printFooter(): void {
?>
</main>
<footer>© 2024 My Site</footer>
<script src="/assets/js/app.js"></script>
</body>
</html>
<?php
}
?>
article.php<?php
require_once 'layout.php';
// 頁面邏輯:獲取文章數據
$article = [
'title' => 'PHP 函數封裝佈局最佳實踐',
'content' => '...文章正文...',
'keywords' => 'PHP, 佈局, 函數封裝',
'description' => '學習用函數替代 require 實現參數化佈局...',
];
// 調用佈局函數,顯式傳參
printHeader(
$article['title'],
['keywords' => $article['keywords'], 'description' => $article['description']],
'blog' // 導航高亮
);
?>
<article>
<h1><?= htmlspecialchars($article['title']) ?></h1>
<div class="content"><?= $article['content'] ?></div>
</article>
<?php
printFooter();
?>
<?php
class Layout {
private string $title = '';
private array $meta = [];
private string $activeNav = '';
private array $blocks = []; // 區塊內容 ['sidebar' => '...']
public function title(string $t): self { $this->title = $t; return $this; }
public function meta(array $m): self { $this->meta = array_merge($this->meta, $m); return $this; }
public function activeNav(string $n): self { $this->activeNav = $n; return $this; }
public function block(string $name, string $content): self { $this->blocks[$name] = $content; return $this; }
public function renderHeader(): void {
// 同 printHeader 邏輯,使用 $this->title 等屬性
// 區塊輸出:echo $this->blocks['sidebar'] ?? '';
}
public function renderFooter(): void { /* ... */ }
}
// 使用
$layout = new Layout();
$layout->title('文章頁')
->meta(['description' => '...'])
->activeNav('blog')
->block('sidebar', '<aside>側邊欄內容</aside>');
$layout->renderHeader();
?>
<article>...</article>
<?php $layout->renderFooter(); ?>
最佳實踐:小項目用函數封裝;中大型項目結合模板引擎(Twig/Blade/Smarty),佈局函數作為控制器與模板的適配層,負責數據預處理、區塊組裝,模板專注輸出渲染。