
资料在文章末尾
这是 PHP 入门系列的第三篇。前两篇讲完了变量、数据类型和运算符,代码还只会从头到尾顺次执行。这一篇解决两个问题:让代码能根据不同情况走不同分支,以及把重复的逻辑封装成可复用的函数。涉及 if/switch 条件判断、while/for/foreach 循环、break/continue 跳转、自定义函数、参数返回值、作用域、匿名函数和箭头函数。每个知识点都配可直接运行的代码,建议边看边敲。
到目前为止,我们写的代码都是从上到下逐行执行,没有分叉。但真实业务里,代码必须应对各种情况:用户登录没?年龄够不够?购物车是不是空的?这些都要靠条件判断来处理。需要重复执行某段逻辑时(比如处理一批数据),就用循环。把常用逻辑提取出来做成函数,代码就能像搭积木一样组合复用。
本篇的知识链路:条件判断 → switch 多分支 → 循环结构 → 循环控制 → 函数定义与调用 → 参数与返回值 → 作用域 → 匿名与箭头函数。
最简单的判断:条件为 true 就执行大括号里的代码,为 false 就跳过。
<?php$weather = "rain";if ($weather == "rain") { echo "带上雨伞!";}?>条件不满足时,执行 else 里的代码。
<?php$weather = "sunny";if ($weather == "rain") { echo "带上雨伞!";} else { echo "戴上帽子!";}?>多个条件依次判断,遇到第一个满足的就执行,后面的不再判断。
<?php$temperature = 22;if ($temperature < 10) { echo "穿羽绒服";} elseif ($temperature >= 10 && $temperature <= 20) { echo "穿外套";} else { echo "穿 T 恤";}?>elseif 可以写多个,最后一个 else 可以省略。
if 可以嵌套使用,但层级别太深,超过三层就该考虑重构了。
<?php$is_logged = true;$is_admin = true;if ($is_logged) { if ($is_admin) { echo "进入管理后台"; } else { echo "进入用户中心"; }} else { echo "请先登录";}?>代码风格上建议遵循 PSR-12:if 后跟一个空格,大括号风格团队统一即可,缩进用 4 个空格。
PHP 嵌入大量 HTML 时,用 if(): ... endif; 语法更清晰,避免大括号难以配对。
<?php if ($logged_in): ?> <p>欢迎回来,<?= $username ?></p><?php else: ?> <p>请<a href="login.php">登录</a></p><?php endif; ?><?= $var ?>是 <?php echo $var; ?>的简写,输出变量很方便。
当一个变量要和多个确定值比较时,switch 比一串 elseif 更清晰。
<?php$choice = 2;switch ($choice) { case 1: echo "你选择了可乐。"; break; case 2: echo "你选择了雪碧。"; break; case 3: echo "你选择了果汁。"; break; default: echo "无效选择!"; break;}?>三个关键点:
• case 之间是松散比较(==),不区分类型
• 每个 case 末尾的 break 不能漏,否则会发生"穿透",继续执行下一个 case
• default 相当于 else,所有 case 都不匹配时执行
穿透不一定是 bug,有时可以故意利用。比如让多个 case 共用同一段代码:
<?php$day = "Wednesday";switch ($day) { case "Friday": echo "TGIF!"; break; case "Wednesday": case "Thursday": echo "快到周末了!"; break; default: echo "普通工作日";}?>Wednesday 和 Thursday 共用一段输出。判断变量是否等于某个具体值用 switch,涉及范围或逻辑运算用 if。
先判断条件,为 true 就执行循环体,执行完再判断,直到条件为 false 退出。条件一开始就是 false 的话,循环体一次都不执行。
<?php$hungry = 3; // 吃 3 口饱while ($hungry > 0) { echo "吃一口饭。\n"; $hungry--;}echo "饱了!";?>输出:吃一口饭。×3,最后输出"饱了!"。
先执行一次循环体,再判断条件。即使条件一开始就不满足,也会执行一次。
<?php$energy = 0;do { echo "玩了一把游戏。\n"; $energy--;} while ($energy > 0);?>即使 $energy = 0,也会输出一次"玩了一把游戏。"。
最常用的计数循环。语法:for (初始化; 条件; 每次循环后操作) { ... }
<?phpfor ($i = 1; $i <= 10; $i++) { echo "俯卧撑第 $i 个\n";}?>三个部分的作用:
• 初始化($i = 1):只执行一次
• 条件($i <= 10):每次循环前检查,为 false 就退出
• 每次循环后操作($i++):循环体执行完后执行
三个部分都能省略(但分号不能省),比如无限循环写成 for (;;) { ... }。
foreach 专门用来遍历数组,有两种写法。
只取值:
<?php$fruits = ["苹果", "香蕉", "橘子"];foreach ($fruits as $fruit) { echo "水果:$fruit\n";}?>同时取键和值:
<?php$user = [ "name" => "张三", "age" => 25, "city" => "上海"];foreach ($user as $key => $value) { echo "$key: $value\n";}?>foreach 也能遍历对象的公共属性,处理数据库结果集时用得非常多。
找到目标就立刻退出循环,不再继续。
<?phpfor ($i = 1; $i <= 10; $i++) { if ($i == 5) { echo "找到钥匙,在第 $i 个房间!"; break; } echo "搜索第 $i 个房间...\n";}?>输出搜索 1-4 房间,找到第 5 个后立即跳出,不再执行 6-10。
不退出循环,只是跳过当前这一轮剩下的代码,直接进入下一轮。
<?phpfor ($i = 1; $i <= 5; $i++) { if ($i == 3) { echo "第 $i 个不合格,跳过。\n"; continue; } echo "第 $i 个产品合格,包装。\n";}?>第 3 个被跳过,其余都正常处理。
break 2 可以跳出两层嵌套循环,continue 2 跳过外层循环的本次迭代。可读性差,实际项目里尽量少用。
函数是一段可重复使用的代码块,给它一个名字,传入参数,它执行任务并可能返回结果。
<?phpfunction greet() { echo "你好,欢迎!";}greet(); // 输出:你好,欢迎!?>函数名推荐小写加下划线,见名知义。
<?phpfunction greet($name) { echo "你好,$name!";}greet("小明"); // 输出:你好,小明!greet("小红"); // 输出:你好,小红!?>多个参数用逗号分隔。
函数可以返回计算结果。一旦执行 return,函数立即结束。没有 return 的函数默认返回 NULL。
<?phpfunction multiply($x, $y) { return $x * $y;}$result = multiply(4, 5);echo $result; // 20?>调用时不传该参数,就用默认值。带默认值的参数必须放在非默认参数后面。
<?phpfunction order($food, $drink = "水") { echo "你点了 $food 和 $drink。";}order("汉堡", "可乐"); // 你点了汉堡和可乐。order("披萨"); // 你点了披萨和水。?>可变参数(PHP 5.6+):用 ... 接收任意数量参数,会被打包成数组。
<?phpfunction sum(...$numbers) { $total = 0; foreach ($numbers as $n) { $total += $n; } return $total;}echo sum(1, 2, 3, 4); // 10?>可以给参数和返回值指定类型,提前拦截类型错误。
<?phpfunction divide(int $a, int $b): float { return $a / $b;}echo divide(10, 3); // 3.333...?>默认情况下 PHP 会尝试自动转换类型("10" 转 10)。要严格检查,在文件首行加 declare(strict_types=1);。
<?phpdeclare(strict_types=1);function add(int $a, int $b): int { return $a + $b;}add("10", 20); // 报错!必须传整数类型?>可声明的类型:int、float、string、bool、array、object、iterable、callable、类/接口名,PHP 8.0+ 还支持 mixed 和联合类型(int|string)。
函数内部定义的变量是局部变量,外部不可见。外部定义的全局变量,在函数内部默认也不可见。
<?php$global_var = "外面";function test() { $local_var = "里面"; echo $local_var; // 输出 "里面" // echo $global_var; // 报错!Undefined variable}test();// echo $local_var; // 报错!Undefined variable?>函数内部要访问全局变量,用 global 关键字声明,或用 $GLOBALS 超全局数组。
<?php$name = "全局张三";function show() { global $name; echo $name; // 输出 "全局张三" $name = "被函数修改";}show();echo $name; // 输出 "被函数修改"?>实际项目中尽量别用全局变量,会让代码难以调试。需要外部数据时,通过参数传入函数。
函数执行完,局部变量通常会被销毁。用 static 声明的变量,在多次调用之间会保留值,只在第一次调用时初始化。
<?phpfunction counter() { static $count = 0; $count++; echo $count . " ";}counter(); // 1counter(); // 2counter(); // 3?>没有名字的函数,可以赋值给变量,也可以作为参数传给其他函数。
<?php$greet = function($name) { echo "你好,$name!";};$greet("小明"); // 你好,小明!?>匿名函数要使用外部变量,用 use 关键字引入。默认是传值,要修改外部变量用 use (&$var)。
<?php$msg = "欢迎";$greet = function($name) use ($msg) { echo "$msg,$name!";};$greet("小红"); // 欢迎,小红!?>更简洁的匿名函数写法,自动捕获外部变量(按值),只能写一个表达式,自动返回。
<?php$factor = 3;$multiply = fn($x) => $x * $factor;echo $multiply(5); // 15?>把前面学的流程控制和函数整合起来,写一个完整的成绩管理小程序。功能包括:录入成绩、修改分数、删除学生、自动评级、计算平均分和极值、数据持久化(session 存储,刷新页面不丢)。
<?phpsession_start();// 初始化会话存储成绩数组,刷新页面数据不消失if (!isset($_SESSION['student_scores'])) { $_SESSION['student_scores'] = [ "张三" => 92.5, "李四" => 78.0, "王五" => 85.5, "赵六" => 61.0, "孙七" => 45.5, ];}$student_scores = $_SESSION['student_scores'];// 删除学生逻辑$msg = "";if (isset($_GET['delname'])) { $delName = $_GET['delname']; if (isset($student_scores[$delName])) { unset($student_scores[$delName]); $_SESSION['student_scores'] = $student_scores; $msg = "已删除学生:{$delName}"; } header("Location: ".$_SERVER['PHP_SELF']); exit;}// 接收表单提交数据(新增/修改)$error = "";if ($_SERVER["REQUEST_METHOD"] === "POST") { $name = trim($_POST['name'] ?? ""); $score = trim($_POST['score'] ?? ""); if ($name === "") { $error = "姓名不能为空!"; } elseif (!is_numeric($score) || $score < 0 || $score > 100) { $error = "分数必须是0~100之间的数字!"; } else { // 同名覆盖 = 修改分数;新名字 = 新增学生 $student_scores[$name] = (float)$score; $_SESSION['student_scores'] = $student_scores; header("Location: ".$_SERVER['PHP_SELF']); exit; }}// 根据分数获取等级function getGrade(float $score): string { if ($score >= 90) return "A"; elseif ($score >= 80) return "B"; elseif ($score >= 70) return "C"; elseif ($score >= 60) return "D"; else return "F";}// 计算平均分function average(array $scores): float { $total = 0; $count = 0; foreach ($scores as $score) { $total += $score; $count++; } return $count > 0 ? $total / $count : 0.0;}$avg = average($student_scores);// 遍历找出最高分、最低分、对应学生$max_score = 0;$max_student = "";$min_score = 100;$min_student = "";foreach ($student_scores as $name => $score) { if ($score > $max_score) { $max_score = $score; $max_student = $name; } if ($score < $min_score) { $min_score = $score; $min_student = $name; }}?><!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <title>学生成绩管理系统</title> <style> .wrap { width: 500px; margin: 30px auto; text-align: center; } table { border-collapse: collapse; width: 480px; margin: 20px auto; } th, td { border: 1px solid #999; padding: 8px 10px; text-align: center; } th { background-color: #f5f5f5; } .form-box { border: 1px solid #ccc; padding: 15px; width: 480px; margin: 0 auto 20px; } .error { color: red; margin: 10px 0; } .success { color: green; } input { padding: 6px; margin: 5px; width: 160px; } button { padding: 6px 16px; background: #007bff; color: white; border: none; cursor: pointer; } .del-btn { background: #dc3545; padding: 4px 10px; color: #fff; text-decoration: none; font-size: 14px; } </style></head><body> <div class="wrap"> <h2>学生成绩管理系统</h2> <?php if ($msg): ?> <div class="success"><?php echo $msg; ?></div> <?php endif; ?> <div class="form-box"> <h3>新增/修改学生成绩</h3> <?php if ($error): ?> <div class="error"><?php echo $error; ?></div> <?php endif; ?> <form method="post" action=""> <label>学生姓名: <input type="text" name="name" placeholder="输入姓名,同名自动修改分数"> </label> <br> <label>考试分数: <input type="number" step="0.5" min="0" max="100" name="score" placeholder="0~100"> </label> <br> <button type="submit">提交保存</button> </form> </div> <h3>======= 成绩报告 =======</h3> <table> <tr> <th>姓名</th> <th>分数</th> <th>等级</th> <th>操作</th> </tr> <?php foreach ($student_scores as $name => $score): ?> <tr> <td><?php echo $name; ?></td> <td><?php echo $score; ?></td> <td><?php echo getGrade($score); ?></td> <td> <a class="del-btn" href="?delname=<?php echo urlencode($name); ?>" onclick="return confirm('确定删除该学生?')">删除</a> </td> </tr> <?php endforeach; ?> </table> <p>平均分:<?php echo number_format($avg, 2); ?></p> <p>最高分:<?php echo $max_student; ?>(<?php echo $max_score; ?> 分)</p> <p>最低分:<?php echo $min_student; ?>(<?php echo $min_score; ?> 分)</p> <p>当前总人数:<?php echo count($student_scores); ?> 人</p> </div></body></html>会话初始化
session_start();if (!isset($_SESSION['student_scores'])) { $_SESSION['student_scores'] = [ /* 初始5名学生 */ ];}$student_scores = $_SESSION['student_scores'];• session_start() 开启会话,浏览器会话期间数据临时保存,刷新页面不丢
• isset() 判断会话中是否已有成绩数组,没有就加载初始数据
• 关闭浏览器后会话销毁,数据清空(这是 session 的特性,不是 bug)
表单接收与校验
if ($_SERVER["REQUEST_METHOD"] === "POST") { $name = trim($_POST['name'] ?? ""); $score = trim($_POST['score'] ?? ""); if ($name === "") { $error = "姓名不能为空!"; } elseif (!is_numeric($score) || $score < 0 || $score > 100) { $error = "分数必须是0~100之间的数字!"; } else { $student_scores[$name] = (float)$score; $_SESSION['student_scores'] = $student_scores; header("Location: ".$_SERVER['PHP_SELF']); exit; }}• trim() 清除输入首尾空格,?? "" 防止未传参时报错
• 三层校验:姓名非空、分数为数字、分数区间 0-100
• 同名覆盖实现修改分数功能,新名字实现新增学生
• header() 自刷新页面,避免用户重复提交表单
等级判定与平均分函数
function getGrade(float $score): string { if ($score >= 90) return "A"; elseif ($score >= 80) return "B"; elseif ($score >= 70) return "C"; elseif ($score >= 60) return "D"; else return "F";}function average(array $scores): float { $total = 0; $count = 0; foreach ($scores as $score) { $total += $score; $count++; } return $count > 0 ? $total / $count : 0.0;}• 两个函数都用了类型声明:参数类型和返回值类型都明确指定
• average 里的三元判断防止数组为空时除以 0 报错
极值统计
$max_score = 0; $max_student = "";$min_score = 100; $min_student = "";foreach ($student_scores as $name => $score) { if ($score > $max_score) { $max_score = $score; $max_student = $name; } if ($score < $min_score) { $min_score = $score; $min_student = $name; }}• 预设最大值初始为 0、最小值初始为 100,foreach 遍历时实时更新
删除逻辑
if (isset($_GET['delname'])) { $delName = $_GET['delname']; if (isset($student_scores[$delName])) { unset($student_scores[$delName]); $_SESSION['student_scores'] = $student_scores; $msg = "已删除学生:{$delName}"; } header("Location: ".$_SERVER['PHP_SELF']); exit;}• GET 参数接收删除指令,unset() 删除数组指定键
• 前端删除按钮用 urlencode() 防中文乱码,onclick confirm() 二次确认防误删
把代码保存为 grade.php,放到 xampp/htdocs 目录,浏览器访问 http://localhost/grade.php,页面会加载 5 条初始学生数据。

功能验证清单:
• 新增学生:输入全新姓名 + 分数,提交后表格多一行,总人数 +1


• 修改分数:输入已有姓名 + 新分数,提交后对应行分数更新


• 姓名为空:红色提示"姓名不能为空!"

• 分数越界:输入 105 或 -5,提示"分数必须是0~100之间的数字!"


• 数据持久化:刷新页面,数据不丢失;关闭浏览器重开,数据清空
• 自动评级:90+ 为 A,80-89 为 B,70-79 为 C,60-69 为 D,60 以下为 F
• 极值统计:多组数据下,自动展示当前最高分和最低分学生
• 删除功能:点删除按钮弹窗确认,确认后该行消失,统计自动重算


• 条件判断:if/else/elseif 处理分支逻辑,switch 适合多值匹配,注意 break 不能漏
• 循环:while 先判断后执行,do...while 至少执行一次,for 适合计数循环,foreach 专门遍历数组
• 循环控制:break 跳出整个循环,continue 跳过本次
• 函数:function 定义,参数传入、return 返回。支持默认值、可变参数、类型声明
• 作用域:局部和全局隔离,优先用参数传值,少用 global;static 变量跨调用保留
• 匿名函数与箭头函数:现代 PHP 的简洁写法,常用于回调和临时逻辑
本文基于作者实际学习与项目经验整理,代码示例均已在本地环境测试通过。文字整理过程中借助了 AI 工具辅助排版。

本文配套资料包
资料下载

-END-
