第四章:PHP流程控制——让代码学会“思考”和“重复”

流程控制,说白了就是让代码能根据不同的情况做不同的事,或者反复做同一件事。这是编程的骨架,没有它,代码就是一潭死水。我个人习惯把流程控制分成两大类:分支判断循环迭代。今天咱们就把它们彻底聊透。

4.1 if-else 判断:最基础的分支逻辑

if-else 是 PHP 里最常用的判断结构。它的逻辑很简单:如果条件成立,就执行 A;否则执行 B

<?php
$score = 85;

if ($score >= 90) {
    echo "优秀";
} elseif ($score >= 80) {
    echo "良好";
} elseif ($score >= 60) {
    echo "及格";
} else {
    echo "不及格";
}
// 输出:良好
?>

这里有个小细节:elseif 可以连着写,但要注意条件的顺序。我建议把最严格的条件放在最前面,否则后面的分支可能永远执行不到。

注意: 我曾经在项目中见过有人把 elseif 写成 else if(中间有空格)。虽然 PHP 也支持,但为了代码风格统一,我建议始终使用 elseif

4.2 switch 分支:多路选择的优雅写法

当你要判断的变量只有几个固定值时,switch 比 if-else 更清晰。你想想看,如果写一堆 elseif 去比较同一个变量,是不是很啰嗦?

<?php
$day = "Monday";

switch ($day) {
    case "Monday":
        echo "新的一周开始了";
        break;
    case "Friday":
        echo "明天就周末了";
        break;
    case "Saturday":
    case "Sunday":
        echo "周末愉快";
        break;
    default:
        echo "普通工作日";
}
?>

嗯,这里要注意 break。如果你忘了写 break,代码会继续往下执行下一个 case,这叫“穿透”。有时候我们故意利用穿透(比如上面的 Saturday 和 Sunday 共用一段代码),但更多时候它是 bug 的来源。

我的习惯: 每个 case 后面都写 break,哪怕只有一行代码。这样以后修改时不容易出错。

4.3 while 循环:先判断,后执行

while 循环的逻辑是:只要条件为真,就一直执行循环体。它适合那种“不知道要循环多少次”的场景。

<?php
$i = 1;
while ($i <= 5) {
    echo "第 {$i} 次循环\n";
    $i++;
}
// 输出 1 到 5
?>

这里有个经典陷阱:死循环。如果你忘了写 $i++,条件永远为真,程序就会卡死。我在刚学 PHP 时干过这事,浏览器直接崩溃了。

4.4 do-while 循环:先执行,后判断

do-while 和 while 的唯一区别:它至少会执行一次循环体。因为条件判断在循环体后面。

<?php
$i = 10;
do {
    echo "至少执行一次";
    $i++;
} while ($i <= 5);
// 输出:至少执行一次
?>

你看,即使条件不成立,它也执行了一次。这种结构在“先做一次,再决定要不要继续”的场景下很实用。比如用户输入验证,先提示一次,如果输入不对再继续提示。

4.5 for 循环:最经典的计数循环

for 循环适合明确知道循环次数的场景。它的语法稍微复杂一点,但用熟了会觉得非常顺手。

<?php
for ($i = 0; $i < 10; $i++) {
    echo "当前值:{$i}\n";
}
?>

for 循环的三个部分:初始化条件判断步进更新。我个人习惯把循环变量命名为 $i$j$k,嵌套循环时依次递增。

性能小贴士: 如果循环次数很大(比如上万次),建议把 count() 这类函数放在循环外面计算。否则每次循环都调用一次函数,性能会受影响。

4.6 foreach 循环:遍历数组的利器

foreach 是 PHP 里我最喜欢的循环结构。它专门用来遍历数组,不需要关心下标,也不需要手动控制循环变量。

<?php
$users = ["张三", "李四", "王五"];

foreach ($users as $name) {
    echo "用户:{$name}\n";
}

// 带键名的遍历
$scores = ["张三" => 90, "李四" => 85];
foreach ($scores as $name => $score) {
    echo "{$name} 的成绩是 {$score}\n";
}
?>

foreach 遍历的是数组的副本,也就是说你在循环里修改 $name 不会影响原数组。如果你想修改原数组,需要加 & 引用符号。

注意: 使用引用时一定要小心。循环结束后,$name 仍然保留着对最后一个元素的引用。如果不小心再次使用 $name,可能会意外修改数组。我建议循环结束后立即 unset($name)

4.7 break 与 continue:控制循环的“刹车”和“跳过”

这两个关键字用来精细控制循环的执行流程

  • break:立即终止整个循环,跳出循环体。
  • continue:跳过当前这次循环的剩余代码,直接进入下一次循环。
<?php
// break 示例:找到第一个大于 50 的数就停止
$numbers = [10, 20, 55, 30, 70];
foreach ($numbers as $num) {
    if ($num > 50) {
        echo "找到:{$num}";
        break;  // 找到后立即停止
    }
}

// continue 示例:跳过偶数
for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 == 0) {
        continue;  // 跳过偶数
    }
    echo "奇数:{$i}\n";
}
?>

break 还可以接受一个数字参数,表示跳出几层循环。比如 break 2 表示跳出两层嵌套循环。不过我个人不太推荐这么用,代码可读性会下降。如果嵌套太深,不如把内层循环抽成函数。

我的经验: 在 foreach 循环里用 continue 时,要注意它不会跳过循环变量的更新。foreach 的循环变量是自动管理的,continue 只是跳过当前迭代的剩余代码。

4.8 实战建议:如何选择合适的循环

场景 推荐循环 原因
遍历数组 foreach 最简洁,不需要手动管理下标
已知循环次数 for 语法清晰,初始化/条件/步进一目了然
未知循环次数,先判断 while 条件在循环体前面,逻辑直观
至少执行一次 do-while 先执行后判断,保证至少运行一次
多分支固定值判断 switch 比 if-else 更清晰,支持穿透

最后说一句:不要滥用循环。有时候用数组函数(如 array_maparray_filter)能写出更简洁的代码。但如果你刚开始学,先用循环把逻辑跑通,再考虑优化也不迟。

好了,流程控制这块就聊到这。下一章咱们会深入函数和命名空间,那才是真正开始搭建项目骨架的时候。