第2章 2.5 综合实战:BMI 计算器 + 猜数字

🎯 开场 3 分钟:为什么要学这个?

上完一节课,你是不是这种感觉——

"知识点好像都懂了,但让我自己写个东西,还是不知道从哪下手?"

正常,太正常了。 就像你背了游泳动作口诀,但第一次下水还是会慌。

这一章,就是帮你跨过这个坎的。

我们要把前几章学的 变量、条件判断、循环、函数、作用域、匿名函数 全都用上,从零开始做两个真实的小工具:

  • BMI 计算器——输入身高体重,告诉你体型是否健康
  • 猜数字游戏——程序随机想一个数,你来猜,猜对了恭喜,猜错了告诉你偏大还是偏小

听起来简单?但我们用 HTML + PHP 混编 的方式做,页面好看,还能跑起来发给朋友炫耀。

学完这章,你就不再是"会写 PHP 语法"的人了,而是"能用自己的代码解决具体问题"的人。


🧱 基础 25 分钟:核心概念扫盲

2.5.1 为什么要用「HTML + PHP 混编」?

之前我们写的 PHP 都是纯逻辑,输入输出全靠 echo\n\n![Simple tech illustration expla](https://blog.xxyye.com/wp-content/uploads/2026/06/874b9df03fae490.png)\n\n![AI comic creation scene, creat](https://blog.xxyye.com/wp-content/uploads/2026/06/7eb021a2227b5ce.png)\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 点

  1. HTML + PHP 混编:HTML 画表单,PHP 做计算,通过 $_POST 传递数据
  2. $_SESSION 会话存储:像保险箱一样,页面刷新也不丢数据,适合猜数字这种需要"记住状态"的场景
  3. 匿名函数封装逻辑:把判断逻辑塞进变量里,代码更整洁,逻辑更清晰

延伸学习资源

互动钩子

你有没有遇到过这种情况:表单填了半天,点提交,结果页面空白?当时是怎么解决的?评论区聊聊,老粉优先回复!


下章预告

学会了 BMI 计算器和猜数字,你有没有想过——如果我有 一堆数据 要处理怎么办?比如全班 50 个人的身高体重,能不能一次算完?下节课我们要讲的「数组」,就是处理批量数据的利器……

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。