PHP 条件判断与循环
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
PHP 的流程控制语法与其他语言相似,但有两点是 PHP 特有的:match 表达式(PHP 8 起,比 switch 好用得多)和模板替代语法。
if / elseif / else
$score = 85;
if ($score >= 90) {
echo "优秀";
} elseif ($score >= 60) {
echo "及格";
} else {
echo "不及格";
}
elseif 在 PHP 里也可以写成 else if,两者等价,风格上统一用 elseif。
三元运算符与空值合并:
$label = $score >= 60 ? "及格" : "不及格";
$name = $_GET["name"] ?? "匿名"; // 仅当 null / 未设置时兜底
?? 可以链式使用:$a ?? $b ?? "默认"。
switch 的问题
switch ($status) {
case "pending":
echo "等待处理";
break;
case "done":
echo "已完成";
break;
default:
echo "未知状态";
}
switch 用 ==(松散比较)且必须手动 break,漏写会继续执行下一个分支。"1" 与 1 会互相匹配,这是很多 bug 的来源。
match 表达式(推荐)
PHP 8 引入 match,三个改进:严格比较(===)、无需 break、有返回值。
$status = "pending";
$message = match ($status) {
"pending" => "等待处理",
"done" => "已完成",
"failed" => "失败",
default => "未知状态",
};
echo $message; // 等待处理
多个条件合并与在分支里执行逻辑:
$level = match (true) {
$score >= 90 => "优秀",
$score >= 60 => "及格",
default => "不及格",
};
没有匹配且没有 default 时会抛 UnhandledMatchError,这比 switch 静默跳过更安全。
结论:PHP 8+ 里需要等值匹配时优先 match,switch 只用于需要 fall-through 的少数场景。
for
次数确定的循环:
for ($i = 0; $i < 3; $i++) {
echo $i . "\n";
}
遍历数组时不要用 for,用 foreach——PHP 数组的键不一定是连续整数,for 会漏项或报未定义下标。
foreach(主力)
$colors = ["red", "green", "blue"];
foreach ($colors as $color) {
echo $color . "\n";
}
foreach ($colors as $index => $color) {
echo "$index => $color\n";
}
foreach 遍历的是副本。要在循环中修改元素值:
foreach ($colors as &$color) {
$color = strtoupper($color);
}
unset($color); // 必须断开引用
忘记 unset 会导致之后再使用 $color 这个变量名时,意外修改数组最后一个元素——这是很难查的 bug。
while 与 do-while
次数不确定时用 while:
$retry = 0;
while ($retry < 3) {
echo "第 " . ($retry + 1) . " 次尝试\n";
$retry++;
}
do-while 至少执行一次:
do {
$input = trim(fgets(STDIN));
} while ($input === "");
写 while 时先确认退出条件可达,否则死循环。
break 与 continue
foreach ([1, 2, 3, 4, 5] as $n) {
if ($n === 2) {
continue; // 跳过本次
}
if ($n === 4) {
break; // 结束整个循环
}
echo $n . "\n";
}
// 输出 1 3
continue 2 / break 2 可以指定跳出几层嵌套(用于嵌套循环):
foreach ($rows as $row) {
foreach ($row as $cell) {
if ($cell === null) {
continue 2; // 跳过外层本次迭代
}
echo $cell;
}
}
数字层数容易写错,嵌套超过两层就该考虑拆成函数。
模板替代语法
在 HTML 模板里混用大括号会降低可读性,PHP 提供了冒号 + end 关键字的替代写法:
<?php if ($loggedIn): ?>
<p>欢迎回来</p>
<?php else: ?>
<p><a href="/login">请登录</a></p>
<?php endif; ?>
<ul>
<?php foreach ($items as $item): ?>
<li><?= htmlspecialchars($item, ENT_QUOTES, "UTF-8") ?></li>
<?php endforeach; ?>
</ul>
几点说明:
<?=是<?php echo的简写,PHP 5.4 起始终可用。- 输出到 HTML 必须转义(
htmlspecialchars),详见本系列第 5 篇。 endif/endforeach/endwhile/endfor与对应的冒号开头配对。
一个完整例子:分组渲染
<?php
declare(strict_types=1);
$orders = [
["id" => 1, "status" => "pending"],
["id" => 2, "status" => "done"],
["id" => 3, "status" => "pending"],
];
$groups = [];
foreach ($orders as $order) {
$groups[$order["status"]][] = $order["id"];
}
foreach ($groups as $status => $ids) {
$label = match ($status) {
"pending" => "待处理",
"done" => "已完成",
default => "其他",
};
echo $label . ":" . implode(", ", $ids) . PHP_EOL;
}
// 待处理:1, 3
// 已完成:2
常见错误与注意事项
switch漏写break:连续执行后续分支。改用match可从根上避免。switch的松散比较:"1"匹配1,match用===。match没有default且未匹配:抛UnhandledMatchError,记得给default。foreach引用后不unset:后续同名变量会污染数组最后一个元素。- 用
for遍历关联数组:下标不存在,报未定义偏移。一律用foreach。 while循环变量不更新:死循环。
小结
- 等值分支用
match(严格比较、有返回值、无需 break)。 - 遍历数组用
foreach,不要用for。 - 引用遍历后必须
unset。 - HTML 模板用替代语法
if: ... endif;与<?= ?>短输出。