`标签外面,中中结果页面直接崩掉。将数据库其实核心就一句话:PHP负责取数据,数据HTML负责摆位置,显示两者用PHP的网页模板语法混着写就行。 假设你有个MySQL数据库,中中里面存着用户留言。将数据库表名叫`messages`,数据字段有`id`、显示`name`、网页`content`、`created_at`。先连库,用PDO或者mysqli都行。我习惯PDO,写起来干净:
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '123456'); $stmt = $pdo->query('SELECT * FROM messages ORDER BY created_at DESC'); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
到这里,`$rows`就是一个二维数组,每个元素对应一条留言。接下来是重点:怎么把它变成网页上的列表。别急着关掉PHP标签再写HTML,那样反而绕。直接在PHP文件里写HTML,遇到要循环的地方再打开`<?php ?>`。比如:
<!DOCTYPE html> <html> <head><meta charset="utf-8"><title>留言板</title></head> <body> <h1>全部留言</h1> <?php if (empty($rows)): ?> <p>还没有留言。</p> <?php else: ?> <ul> <?php foreach ($rows as $row): ?> <li> <strong><?= htmlspecialchars($row['name']) ?></strong> <span><?= $row['created_at'] ?></span> <p><?= nl2br(htmlspecialchars($row['content'])) ?></p> </li> <?php endforeach; ?> </ul> <?php endif; ?> </body> </html>
注意几个细节。`htmlspecialchars()`不是可选项,是必须的。用户输入的名字里如果带`<script>`,不转义就直接输出,你的页面就变成XSS攻击的靶子。`nl2br()`用来把留言里的换行符变成`<br>`,不然多行文本会挤成一行。还有`<?= ?>`是`<?php echo ?>`的简写,PHP 5.4以后默认开启,用起来省事。
有人喜欢把数据先拼成HTML字符串再`echo`,比如`$html .= '<li>' . $row['name'] . '</li>';`,最后一次性输出。这种写法在逻辑复杂时容易漏掉转义,而且引号嵌套看得眼花。混写模板虽然被某些“架构师”鄙视,但做小项目、快速原型,它就是最直接的。我自己的经验:超过三个嵌套循环或者条件判断,再考虑用模板引擎,否则原生PHP够用。
另一个常见坑是编码。数据库连的时候设了`charset=utf8`,HTML里也写了`<meta charset="utf-8">`,但页面还是乱码。检查一下PHP文件本身是不是UTF-8无BOM格式。Windows记事本默认存成带BOM的UTF-8,BOM字符会跑到HTML前面,导致浏览器解析出错。用VS Code或者Sublime,右下角切一下编码就行。
如果数据量大,别一次性`fetchAll`。比如留言上万条,全取出来塞数组,内存直接爆。改成`fetch`逐行取,在`while`循环里输出:
$stmt = $pdo->query('SELECT * FROM messages ORDER BY created_at DESC'); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { echo '<li>' . htmlspecialchars($row['name']) . '</li>'; }
这样内存占用稳定,页面还能边取边渲染。不过混写HTML时用`while`不如`foreach`直观,看个人取舍。
最后说个实际案例。我之前帮人改一个留言板,他的代码是先从数据库取数据,用`json_encode`转成JSON,再用JavaScript在前端循环生成DOM。页面加载后空白两秒才出内容,因为多了一次HTTP请求。改成PHP直接输出HTML,首屏时间降到200毫秒以内。不是JS不好,而是这种纯展示场景,服务端渲染更省事。PHP天生就是干这个的,别把它当纯API层用。
把数据摆到网页上,本质就是循环加转义。写多了你会发现,真正花时间的是处理边界情况:空数据、超长文本、特殊字符、分页。但那是下一步的事。先把第一条留言正确显示出来,剩下的慢慢加。