第2章 2.5 综合实战:BMI 计算器 + 猜数字
🎯 开场 3 分钟:为什么要学这个?
上完一节课,你是不是这种感觉——
"知识点好像都懂了,但让我自己写个东西,还是不知道从哪下手?"
正常,太正常了。 就像你背了游泳动作口诀,但第一次下水还是会慌。
这一章,就是帮你跨过这个坎的。
我们要把前几章学的 变量、条件判断、循环、函数、作用域、匿名函数 全都用上,从零开始做两个真实的小工具:
- BMI 计算器——输入身高体重,告诉你体型是否健康
- 猜数字游戏——程序随机想一个数,你来猜,猜对了恭喜,猜错了告诉你偏大还是偏小
听起来简单?但我们用 HTML + PHP 混编 的方式做,页面好看,还能跑起来发给朋友炫耀。
学完这章,你就不再是"会写 PHP 语法"的人了,而是"能用自己的代码解决具体问题"的人。
🧱 基础 25 分钟:核心概念扫盲
2.5.1 为什么要用「HTML + PHP 混编」?
之前我们写的 PHP 都是纯逻辑,输入输出全靠 echo\n\n\n\n\n\n 打印到命令行。但真实世界不是这样的——
你打开一个网页,注册账号、填表单、点按钮,这些交互靠的是 HTML 负责「样子」,PHP 负责「脑子」。
举个例子:
<!-- HTML 负责画表单 -->
<form method="post">
身高(米):<input type="text" name="height"><br>
体重(公斤):<input type="text" name="weight"><br>
<button type="submit">计算 BMI</button>
</form>
<?php
// PHP 负责计算逻辑
if (isset($_POST['height']) && isset($_POST['weight'])) {
$height = $_POST['height'];
$weight = $_POST['weight'];
$bmi = $weight / ($height * $height);
echo "你的 BMI 是:" . round($bmi, 1);
}
?>
一句话解释:HTML 画表单接收用户输入,PHP 接收数据做计算,结果再通过 echo 显示在网页上。这就是「混编」——各干各的,互相配合。
2.5.2 什么是 BMI?为什么要计算它?
BMI(Body Mass Index,身体质量指数)是国际上常用的衡量人体胖瘦程度的标准。
公式超简单:
BMI = 体重(kg) ÷ 身高(m)²
比如你 70 公斤,1 米 75:
BMI = 70 ÷ (1.75)² = 70 ÷ 3.0625 ≈ 22.9
BMI 对应关系:
- < 18.5:偏瘦
- 18.5 ~ 24:正常
- 24 ~ 28:偏胖
- > 28:肥胖
2.5.3 猜数字游戏的逻辑是什么?
猜数字游戏规则:
1. 程序随机想一个 1~100 的整数
2. 你猜一个数
3. 程序告诉你「太大了」「太小了」还是「猜对了」
4. 循环直到猜对为止
这个游戏用到的东西:
- rand() 生成随机数
- while 循环反复猜
- if/else 判断大小
- 匿名函数处理每次猜测的反馈
2.5.4 匿名函数在项目里怎么用?
先回忆一下匿名函数长什么样:
$say_hi = function($name) {
return "你好," . $name;
};
echo $say_hi("小明"); // 输出:你好,小明
在猜数字游戏里,我们可以把「判断逻辑」封装成匿名函数,让代码更清晰:
$check_guess = function($guess, $target) {
if ($guess == $target) {
return "恭喜猜对了!";
} elseif ($guess > $target) {
return "太大了,往小猜!";
} else {
return "太小了,往大猜!";
}
};
echo $check_guess(50, 30); // 输出:太大了,往小猜!
一句话解释:匿名函数就像一张匿名名片——你定义的时候不需要给它起名字,直接赋值给变量,用的时候调变量名就行。
🔥 实战 35 分钟:3 个递进小项目
📌 项目 1:BMI 计算器(跟着抄就能跑)
目标:做一个网页,输入身高体重,输出 BMI 和体型判断
完整代码(保存为 bmi.php):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>BMI 计算器</title>
<style>
body { font-family: "微软雅黑", sans-serif; max-width: 500px; margin: 50px auto; padding: 20px; }
input { padding: 8px; margin: 5px 0; width: 100%; box-sizing: border-box; }
button { background: #4CAF50; color: white; padding: 10px 20px; border: none; cursor: pointer; margin-top: 10px; }
button:hover { background: #45a049; }
.result { margin-top: 20px; padding: 15px; background: #f9f9f9; border-left: 4px solid #4CAF50; }
.warning { border-left-color: #ff9800; }
.danger { border-left-color: #f44336; }
</style>
</head>
<body>
<h1>🧮 BMI 计算器</h1>
<form method="post">
<label>身高(米):</label>
<input type="number" step="0.01" name="height" placeholder="例如:1.75" required>
<label>体重(公斤):</label>
<input type="number" step="0.1" name="weight" placeholder="例如:68.5" required>
<button type="submit">计算 BMI</button>
</form>
<?php
if (isset($_POST['height']) && isset($_POST['weight'])) {
$height = floatval($_POST['height']);
$weight = floatval($_POST['weight']);
// 计算 BMI
$bmi = $weight / ($height * $height);
$bmi = round($bmi, 1);
// 判断体型
if ($bmi < 18.5) {
$level = "偏瘦 📉";
$class = "warning";
} elseif ($bmi < 24) {
$level = "正常 ✅";
$class = "result";
} elseif ($bmi < 28) {
$level = "偏胖 📈";
$class = "warning";
} else {
$level = "肥胖 ⚠️";
$class = "danger";
}
echo "<div class='$class'>";
echo "<strong>你的 BMI:" . $bmi . "</strong><br>";
echo "体型判断:$level";
echo "</div>";
}
?>
</body>
</html>
预期输出(输入身高 1.75,体重 70):
你的 BMI:22.9
体型判断:正常 ✅
一句话解释:floatval() 把表单收到的字符串转成数字,round() 保留一位小数,CSS class 用来给不同体型加上不同颜色的边框。
📌 项目 2:猜数字游戏(加入随机和循环)
目标:程序随机想一个 1~100 的数,用户反复猜测,直到猜对
完整代码(保存为 guess.php):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>猜数字游戏</title>
<style>
body { font-family: "微软雅黑", sans-serif; max-width: 500px; margin: 50px auto; padding: 20px; }
input { padding: 8px; margin: 5px 0; width: 100%; box-sizing: border-box; }
button { background: #2196F3; color: white; padding: 10px 20px; border: none; cursor: pointer; margin-top: 10px; }
button:hover { background: #1976D2; }
.msg { margin: 10px 0; padding: 10px; border-radius: 5px; }
.success { background: #C8E6C9; }
.hint { background: #FFF9C4; }
</style>
</head>
<body>
<h1>🎯 猜数字游戏</h1>
<p>我想了一个 1~100 的数字,你来猜!</p>
<form method="post">
<input type="number" name="guess" min="1" max="100" placeholder="输入 1~100 的数字" required>
<button type="submit">猜!</button>
</form>
<?php
// 初始化:第一次玩或猜对了,重新开始
if (!isset($_SESSION)) {
session_start();
}
if (!isset($_SESSION['target'])) {
$_SESSION['target'] = rand(1, 100);
$_SESSION['attempts'] = 0;
}
if (isset($_POST['guess'])) {
$_SESSION['attempts']++;
$guess = intval($_POST['guess']);
$target = $_SESSION['target'];
// 匿名函数:判断猜测
$check = function($g, $t) {
if ($g == $t) {
return ["恭喜猜对了!答案是 $t", "success"];
} elseif ($g > $t) {
return ["太大了,往小猜~", "hint"];
} else {
return ["太小了,往大猜~", "hint"];
}
};
$result = $check($guess, $target);
echo "<div class='msg " . $result[1] . "'>" . $result[0] . "</div>";
if ($guess == $target) {
echo "<p>你一共猜了 " . $_SESSION['attempts'] . " 次</p>";
echo "<p><a href='?reset=1'>再玩一次</a></p>";
unset($_SESSION['target']);
}
}
// 重置游戏
if (isset($_GET['reset'])) {
session_destroy();
header("Location: guess.php");
}
?>
</body>
</html>
预期输出(假设程序想的是 42):
输入 50 → 太大了,往小猜~
输入 30 → 太小了,往大猜~
输入 42 → 恭喜猜对了!答案是 42
你一共猜了 3 次
再玩一次
一句话解释:$_SESSION 像个保险箱,把随机数和猜测次数存起来,页面刷新也不丢。猜对了用 unset() 清空保险箱,重新开始。
📌 项目 3:BMI + 猜数字 组合工具箱
目标:做一个「小工具箱」网页,把 BMI 计算器和猜数字游戏整合在一起,用户可以切换使用
完整代码(保存为 toolbox.php):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>PHP 小工具箱</title>
<style>
body { font-family: "微软雅黑", sans-serif; max-width: 600px; margin: 30px auto; padding: 20px; }
.tabs { overflow: hidden; background: #eee; margin-bottom: 20px; }
.tabs button { float: left; padding: 12px 20px; border: none; background: #ddd; cursor: pointer; }
.tabs button.active { background: #4CAF50; color: white; }
.tab-content { display: none; padding: 20px; border: 1px solid #ddd; }
.tab-content.active { display: block; }
input { padding: 8px; margin: 5px 0; width: 100%; box-sizing: border-box; }
button.btn-bmi { background: #4CAF50; color: white; padding: 10px 20px; border: none; cursor: pointer; }
button.btn-guess { background: #2196F3; color: white; padding: 10px 20px; border: none; cursor: pointer; }
.result-box { margin-top: 15px; padding: 15px; background: #f9f9f9; border-left: 4px solid #4CAF50; }
.result-hint { background: #FFF9C4; border-left-color: #FFC107; }
.result-success { background: #C8E6C9; border-left-color: #4CAF50; }
</style>
</head>
<body>
<h1>🧰 PHP 小工具箱</h1>
<div class="tabs">
<button class="active" onclick="showTab('bmi')">BMI 计算器</button>
<button onclick="showTab('guess')">猜数字</button>
</div>
<!-- BMI 计算器 -->
<div id="bmi" class="tab-content active">
<h2>🧮 BMI 计算器</h2>
<form method="post">
<label>身高(米):</label>
<input type="number" step="0.01" name="height" placeholder="例如:1.75" required>
<label>体重(公斤):</label>
<input type="number" step="0.1" name="weight" placeholder="例如:68.5" required>
<button type="submit" class="btn-bmi">计算</button>
</form>
<?php
if (isset($_POST['height']) && isset($_POST['weight'])) {
$h = floatval($_POST['height']);
$w = floatval($_POST['weight']);
$bmi = round($w / ($h * $h), 1);
$levels = [
['max' => 18.5, 'text' => '偏瘦 📉', 'class' => 'result-hint'],
['max' => 24, 'text' => '正常 ✅', 'class' => 'result-box'],
['max' => 28, 'text' => '偏胖 📈', 'class' => 'result-hint'],
['max' => PHP_INT_MAX, 'text' => '肥胖 ⚠️', 'class' => 'result-hint']
];
foreach ($levels as $level) {
if ($bmi < $level['max']) {
echo "<div class='$level[class]'>BMI = $bmi → $level[text]</div>";
break;
}
}
}
?>
</div>
<!-- 猜数字 -->
<div id="guess" class="tab-content">
<h2>🎯 猜数字游戏</h2>
<?php
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['target'])) {
$_SESSION['target'] = rand(1, 100);
$_SESSION['count'] = 0;
echo "<p>我已经想好了一个 1~100 的数字,开始猜吧!</p>";
}
if (isset($_POST['guess'])) {
$_SESSION['count']++;
$g = intval($_POST['guess']);
$t = $_SESSION['target'];
if ($g == $t) {
echo "<div class='result-success'>🎉 猜对了!答案是 $t,你猜了 $_SESSION[count] 次!</div>";
echo "<p><a href='?reset=1'>再玩一次</a></p>";
unset($_SESSION['target']);
} elseif ($g > $t) {
echo "<div class='result-hint'>太大了,往小猜~</div>";
} else {
echo "<div class='result-hint'>太小了,往大猜~</div>";
}
}
if (isset($_GET['reset'])) {
session_destroy();
header("Location: toolbox.php");
}
?>
<form method="post" style="margin-top: 15px;">
<input type="number" name="guess" min="1" max="100" placeholder="1~100" required>
<button type="submit" class="btn-guess">猜!</button>
</form>
</div>
<script>
function showTab(tab) {
document.querySelectorAll('.tab-content').forEach(el => el.classList.remove('active'));
document.querySelectorAll('.tabs button').forEach(el => el.classList.remove('active'));
document.getElementById(tab).classList.add('active');
event.target.classList.add('active');
}
</script>
</body>
</html>
预期输出:一个带 Tab 切换的页面,点击不同 Tab 切换 BMI 计算器和猜数字游戏,两个工具共享同一个页面。
一句话解释:session_start() 开启会话,不同 Tab 共用同一个 $_SESSION,猜数字的记录不会因为切换 Tab 而丢失。
💪 进阶 20 分钟:常见坑 + 调试技巧
🕳️ 坑 1:表单提交后数据丢失(没加 method="post")
// ❌ 错误:默认是 GET,URL 会带参数,刷新会重复提交
<form>
<input name="height">
</form>
// ✅ 正确:明确用 POST,刷新不会重复提交
<form method="post">
<input name="height">
</form>
🕳️ 坑 2:$_POST['height'] 取不到值(input 没写 name)
// ❌ 错误:input 没有 name 属性,PHP 收不到
<input type="text" placeholder="身高">
// ✅ 正确:name 是表单字段的"身份证"
<input type="text" name="height">
🕳️ 坑 3:除以零错误(BMI 计算时身高为 0)
// ❌ 危险:用户输入身高 0,PHP 会报除以零警告
$bmi = $weight / ($height * $height);
// ✅ 安全:先检查再计算
if ($height > 0) {
$bmi = $weight / ($height * $height);
} else {
echo "身高必须大于 0!";
}
🕳️ 坑 4:rand() 每次刷新页面都变(没存到 session)
// ❌ 错误:每次刷新页面,$target 都会重新生成
$target = rand(1, 100);
// ✅ 正确:存到 session 里,只在第一次初始化
if (!isset($_SESSION['target'])) {
$_SESSION['target'] = rand(1, 100);
}
$target = $_SESSION['target'];
🕳️ 坑 5:session 没开启就用
// ❌ 错误:直接用 $_SESSION 但没开启 session
$_SESSION['count'] = 0;
// ✅ 正确:先判断再开启
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$_SESSION['count'] = 0;
🔧 调试技巧:临时打印变量值
// 最简单粗暴的调试方式
echo "<pre>";
print_r($_POST);
echo "</pre>";
exit; // 停在这里,后面不执行了
这个技巧叫「断点打印」,相当于游戏里的存档点——看到这行了,先看看变量长什么样,再决定怎么走下一步。
✏️ 练习题 + 作业题
练习题(10 分钟)
练习 1(2 分钟):改 BMI 评判标准
- 输入:身高 1.8m,体重 75kg
- 预期输出:你的 BMI 是 23.1,体型是"正常"
- 提示:代码里判断体型的 if 条件改了啥?
练习 2(2 分钟):BMI 加个身高
- 在项目 1 里加一个判断:只有身高在 0.5~2.5 米之间才计算,否则提示"身高不合理"
- 输入:身高 0.3m,体重 50kg
- 预期输出:身高不合理,请输入真实身高
- 提示:加一个 if 判断高度范围
练习 3(2 分钟):猜数字范围改大
- 把猜数字的范围从 1~100 改成 1~1000
- 输入:500
- 预期输出:取决于程序想的数,可能是"太大了"或"太小了"
- 提示:改 rand(1, 100) 这里
练习 4(2 分钟):猜数字记录历史
- 在猜数字游戏里,用一个数组保存每次猜测的记录
- 输入:猜 30、猜 50、猜 40
- 预期输出:显示「你猜过的数:30, 50, 40」
- 提示:每次猜测时往数组 $_SESSION['history'][] = $guess
练习 5(2 分钟):分析报错
- 用户说「提交表单后页面空白,什么都没显示」
- 预期输出:你能找到原因吗?
- 提示:检查 input 的 name 属性和 PHP 里用的 $_POST['xxx'] 是否一致
作业题(30 分钟~2 小时)
作业:做一个「个人健康小助手」
结合 BMI 计算器和猜数字游戏,做一个综合工具:
- 需求描述:用户可以计算自己的 BMI,也可以玩猜数字游戏放松一下
- 功能点:
1. 顶部 Tab 切换不同工具
2. BMI 计算器:输入身高体重,输出 BMI 值和体型判断
3. 猜数字游戏:程序随机想数,用户反复猜测,记录猜测次数
4. 猜对后显示"恭喜"和总共猜了几次 - 加分项:
1. BMI 计算加入身高合理性检查(0.5~2.5 米)
2. 猜数字游戏加入「历史记录」功能,显示猜过的所有数字 - 验收标准:
- 能跑起来(浏览器打开不报错)
- BMI 计算输出正确
- 猜数字能循环猜测,猜对后能重置
- 代码有适量注释
- 提交方式:保存为
health_helper.php,评论区贴代码或 GitHub 链接
📚 总结 + 资源
这一章的核心 3 点
- HTML + PHP 混编:HTML 画表单,PHP 做计算,通过
$_POST传递数据 $_SESSION会话存储:像保险箱一样,页面刷新也不丢数据,适合猜数字这种需要"记住状态"的场景- 匿名函数封装逻辑:把判断逻辑塞进变量里,代码更整洁,逻辑更清晰
延伸学习资源
- PHP 官方文档:$_SESSION —— 最权威的 session 用法说明
- 《PHP 入门到精通》—— 系统学习 PHP 基础
- MDN Web 文档:HTML 表单 —— 前端同学写的,很通俗
互动钩子
你有没有遇到过这种情况:表单填了半天,点提交,结果页面空白?当时是怎么解决的?评论区聊聊,老粉优先回复!
下章预告:
学会了 BMI 计算器和猜数字,你有没有想过——如果我有 一堆数据 要处理怎么办?比如全班 50 个人的身高体重,能不能一次算完?下节课我们要讲的「数组」,就是处理批量数据的利器……

评论(0)