
本文讲解如何将数据库查询逻辑封装在 php 函数中,避免在函数内直接输出 html 或 echo 数据,而是返回结构化数据,再在 html 模板中安全遍历渲染,兼顾代码可维护性、mvc 分离原则与 xss 防护。
本文讲解如何将数据库查询逻辑封装在 php 函数中,避免在函数内直接输出 html 或 echo 数据,而是返回结构化数据,再在 html 模板中安全遍历渲染,兼顾代码可维护性、mvc 分离原则与 xss 防护。
在 Web 开发中,将数据获取与视图渲染混写(如在函数中直接 echo HTML 或字段值)会导致代码难以复用、测试和维护。上述问题的核心误区在于:getData() 函数既负责查询,又承担了输出职责,且试图在 HTML 中二次遍历已失效的 $stmt 游标——因为 foreach ($stmt as $row) 在函数内部已消耗完毕,外部 $stmt 变量根本不可访问。
✅ 正确做法是遵循「单一职责」与「数据-视图分离」原则:
- 函数只负责获取并返回数据(通常为关联数组或对象数组);
- HTML 模板负责接收数据并安全渲染;
- 数据库连接应尽量复用或通过依赖注入管理(本例为简洁暂保留内置连接,生产环境建议使用连接池或服务容器)。
以下是重构后的完整示例:
<?php
function getData() {
try {
$pdo = new PDO("mysql:host=localhost;dbname=db", 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$sql = "SELECT id, username, email, created_at FROM users"; // 显式指定字段,避免 SELECT *
$stmt = $pdo->prepare($sql);
$stmt->execute();
return $stmt->fetchAll(); // 一次性获取全部结果并返回数组
} catch (PDOException $e) {
error_log("Database query failed: " . $e->getMessage()); // 记录错误,不暴露敏感信息
return []; // 返回空数组,确保调用方始终得到一致类型
}
}
?>在 HTML 模板中调用并渲染(注意:必须在 <tbody> 外部先获取数据):
立即学习“PHP免费学习笔记(深入)”;
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th>注册时间</th>
</tr>
</thead>
<tbody>
<?php $users = getData(); ?>
<?php if (empty($users)): ?>
<tr>
<td colspan="4" class="text-center">暂无用户数据</td>
</tr>
<?php else: ?>
<?php foreach ($users as $user): ?>
<tr>
<td><?php echo htmlspecialchars((int)$user['id']); ?></td>
<td><?php echo htmlspecialchars($user['username'] ?? ''); ?></td>
<td><?php echo htmlspecialchars($user['email'] ?? ''); ?></td>
<td><?php echo htmlspecialchars(date('Y-m-d', strtotime($user['created_at'] ?? 'now'))); ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>? 关键注意事项:
- 绝不直接 echo 用户数据:所有动态内容均需经 htmlspecialchars() 转义,防止 XSS 攻击;
- 显式声明字段:避免 SELECT *,提升可读性、性能及 Schema 变更鲁棒性;
- 错误处理要静默且健壮:生产环境禁用 echo $e->getMessage(),改用 error_log() 并返回默认值(如空数组),避免泄漏数据库结构;
- PDO 预设 fetch 模式:设置 PDO::ATTR_DEFAULT_FETCH_MODE 为 PDO::FETCH_ASSOC,使 fetchAll() 默认返回关联数组,语义更清晰;
- 资源及时释放:$stmt 和 $pdo 在函数结束时自动销毁,无需手动 unset(PHP 垃圾回收机制保障)。
? 进阶建议:未来可进一步解耦,将数据库操作抽离为 Repository 类,使用 PSR-4 自动加载,并配合 Twig/Blade 等模板引擎实现更彻底的逻辑与视图分离。











