循环语句

概述

循环语句是编程中用于重复执行代码块的控制结构。当需要多次执行相同或类似的操作时,循环语句可以大大简化代码,提高效率。PHP提供了几种循环结构:

  • for 循环 - 计数器循环,适用于已知循环次数的场景
  • while 循环 - 条件循环,当条件为真时重复执行
  • do-while 循环 - 后测试循环,至少执行一次
  • foreach 循环 - 数组遍历循环,专门用于遍历数组

for 循环

基本语法

for (初始化表达式; 条件表达式; 递增表达式) {
    // 循环体代码
}

语法说明

  • 初始化表达式:在循环开始前执行一次,通常用于初始化计数器
  • 条件表达式:在每次循环开始前求值,如果为 true 则继续执行循环体
  • 递增表达式:在每次循环结束后执行,通常用于更新计数器
  • 执行顺序:初始化 → 条件判断 → 循环体 → 递增 → 条件判断 → ...

基础示例

<?php
// 基础的 for 循环
echo "=== 基础 for 循环示例 ===<br>";

for ($i = 1; $i <= 5; $i++) {
    echo "第 $i 次循环<br>";
}

// 输出:第 1 次循环、第 2 次循环...第 5 次循环

// 倒序循环
echo "<br>=== 倒序循环 ===<br>";
for ($i = 10; $i >= 1; $i--) {
    echo "$i ";
}
// 输出:10 9 8 7 6 5 4 3 2 1

// 步长为 2 的循环
echo "<br><br>=== 步长为 2 的循环 ===<br>";
for ($i = 0; $i <= 10; $i += 2) {
    echo "$i ";
}
// 输出:0 2 4 6 8 10

// 多个变量的 for 循环
echo "<br><br>=== 多变量初始化 ===<br>";
for ($i = 0, $j = 10; $i < $j; $i++, $j--) {
    echo "i=$i, j=$j<br>";
}
?>

实际应用示例

<?php
// 1. 生成乘法表
echo "=== 九九乘法表 ===<br>";
echo "<table border='1'>";

for ($i = 1; $i <= 9; $i++) {
    echo "<tr>";
    for ($j = 1; $j <= 9; $j++) {
        $product = $i * $j;
        echo "<td>$i × $j = $product</td>";
    }
    echo "</tr>";
}

echo "</table><br>";

// 2. 数组元素处理
$numbers = [1, 2, 3, 4, 5];
$sum = 0;
$factorial = 1;

echo "=== 数组处理 ===<br>";
for ($i = 0; $i < count($numbers); $i++) {
    $sum += $numbers[$i];
    $factorial *= $numbers[$i];
    echo "索引 $i: 值 {$numbers[$i]}, 累计和: $sum<br>";
}

echo "总和: $sum<br>";
echo "阶乘: $factorial<br><br>";

// 3. 字符串处理
$text = "Hello World!";
$reversed = "";

for ($i = strlen($text) - 1; $i >= 0; $i--) {
    $reversed .= $text[$i];
}

echo "原字符串: $text<br>";
echo "反转字符串: $reversed<br><br>";

// 4. 图形输出
echo "=== 星形图案 ===<br>";
for ($i = 1; $i <= 5; $i++) {
    for ($j = 1; $j <= $i; $j++) {
        echo "* ";
    }
    echo "<br>";
}

// 金字塔图案
echo "<br>=== 金字塔图案 ===<br>";
for ($i = 1; $i <= 5; $i++) {
    // 打印空格
    for ($j = 1; $j <= 5 - $i; $j++) {
        echo "&nbsp;";
    }
    // 打印星号
    for ($j = 1; $j <= 2 * $i - 1; $j++) {
        echo "*";
    }
    echo "<br>";
}
?>

while 循环

基本语法

while (条件表达式) {
    // 循环体代码
}

语法说明

  • 条件表达式:在每次循环开始前求值
  • 执行流程:检查条件 → 如果为 true 执行循环体 → 重新检查条件
  • 适用场景:当循环次数不确定,只知道循环条件时使用

基础示例

<?php
// 基础的 while 循环
echo "=== 基础 while 循环 ===<br>";

$count = 1;
while ($count <= 5) {
    echo "计数: $count<br>";
    $count++;
}

// 读取文件内容(模拟)
echo "<br>=== 模拟文件读取 ===<br>";
$lines = ["第一行内容", "第二行内容", "第三行内容"];
$index = 0;

while ($index < count($lines)) {
    echo "读取第 " . ($index + 1) . " 行: {$lines[$index]}<br>";
    $index++;
}

// 用户输入验证(模拟)
echo "<br>=== 用户输入验证 ===<br>";
$attempts = 0;
$maxAttempts = 3;
$correctPassword = "123456";
$userInput = "wrong"; // 模拟错误输入

while ($attempts < $maxAttempts && $userInput !== $correctPassword) {
    $attempts++;
    echo "第 $attempts 次尝试,密码错误<br>";
    // 在实际应用中,这里会提示用户重新输入
    $userInput = ($attempts === 3) ? "123456" : "wrong";
}

if ($userInput === $correctPassword) {
    echo "登录成功!<br>";
} else {
    echo "尝试次数过多,登录失败!<br>";
}
?>

实际应用示例

<?php
// 1. 数据库查询结果处理(模拟)
echo "=== 数据库查询结果处理 ===<br>";

// 模拟数据库查询结果
$databaseResults = [
    ['id' => 1, 'name' => '张三', 'score' => 85],
    ['id' => 2, 'name' => '李四', 'score' => 92],
    ['id' => 3, 'name' => '王五', 'score' => 78],
    ['id' => 4, 'name' => '赵六', 'score' => 88],
    ['id' => 5, 'name' => '钱七', 'score' => 95]
];

$index = 0;
$totalScore = 0;
$passedCount = 0;

while ($index < count($databaseResults)) {
    $student = $databaseResults[$index];
    $totalScore += $student['score'];

    if ($student['score'] >= 60) {
        $passedCount++;
        echo "✅ {$student['name']}: {$student['score']} 分 (及格)<br>";
    } else {
        echo "❌ {$student['name']}: {$student['score']} 分 (不及格)<br>";
    }

    $index++;
}

$averageScore = $totalScore / count($databaseResults);
$passRate = ($passedCount / count($databaseResults)) * 100;

echo "<br>统计结果:<br>";
echo "平均分: " . round($averageScore, 2) . "<br>";
echo "及格率: " . round($passRate, 2) . "%<br>";

// 2. 质数判断
echo "<br>=== 质数判断 ===<br>";

function isPrime($number) {
    if ($number < 2) return false;

    $divisor = 2;
    while ($divisor * $divisor <= $number) {
        if ($number % $divisor == 0) {
            return false;
        }
        $divisor++;
    }
    return true;
}

$testNumbers = [2, 3, 4, 5, 16, 17, 19, 20, 23, 25];

foreach ($testNumbers as $num) {
    if (isPrime($num)) {
        echo "$num 是质数<br>";
    } else {
        echo "$num 不是质数<br>";
    }
}

// 3. 数字反转
echo "<br>=== 数字反转 ===<br>";

function reverseNumber($number) {
    $reversed = 0;
    $original = $number;

    while ($number > 0) {
        $digit = $number % 10;  // 取最后一位
        $reversed = $reversed * 10 + $digit;  // 构建反转数
        $number = (int)($number / 10);  // 去掉最后一位
    }

    return $reversed;
}

$numbersToReverse = [123, 4567, 89, 1001];

foreach ($numbersToReverse as $num) {
    $reversed = reverseNumber($num);
    echo "原数: $num, 反转: $reversed<br>";
}
?>

do-while 循环

基本语法

do {
    // 循环体代码
} while (条件表达式);

语法说明

  • 执行特点:先执行循环体,后检查条件
  • 至少执行一次:即使条件为 false,循环体也会执行一次
  • 适用场景:需要至少执行一次的操作,如用户输入、菜单显示等

基础示例

<?php
// 基础的 do-while 循环
echo "=== 基础 do-while 循环 ===<br>";

$count = 1;
do {
    echo "第 $count 次执行<br>";
    $count++;
} while ($count <= 3);

// 条件不满足的情况
echo "<br>=== 条件不满足的情况 ===<br>";
$count = 5;
do {
    echo "至少执行一次,当前值: $count<br>";
} while ($count <= 3);

// 用户输入验证(模拟)
echo "<br>=== 用户输入验证 ===<br>";
$attempts = 0;
$maxAttempts = 3;

do {
    $attempts++;
    echo "请输入密码 (第 $attempts 次尝试):<br>";
    // 模拟用户输入
    $input = ($attempts === 2) ? "correct" : "wrong";

    if ($input === "correct") {
        echo "密码正确!<br>";
        break;
    }
} while ($attempts < $maxAttempts);

if ($attempts >= $maxAttempts) {
    echo "尝试次数过多!<br>";
}

// 菜单系统
echo "<br>=== 简单菜单系统 ===<br>";
$choice = '';

do {
    echo "==== 主菜单 ===<br>";
    echo "1. 查看信息<br>";
    echo "2. 修改设置<br>";
    echo "3. 退出<br>";
    echo "请选择 (1-3): ";

    // 模拟用户选择
    $choice = '3';
    echo "$choice<br>";

    switch ($choice) {
        case '1':
            echo "显示用户信息<br>";
            break;
        case '2':
            echo "进入设置页面<br>";
            break;
        case '3':
            echo "感谢使用,再见!<br>";
            break;
        default:
            echo "无效选择,请重新输入<br>";
    }
} while ($choice !== '3');
?>

foreach 循环

基本语法

// 遍历数组的值
foreach (数组 as 值) {
    // 循环体代码
}

// 遍历数组的键和值
foreach (数组 as 键 => 值) {
    // 循环体代码
}

语法说明

  • 专门用于数组:foreach 是 PHP 中专门用于遍历数组的循环结构
  • 键值对:可以同时获取数组的键和值
  • 简化操作:相比 for 循环,foreach 更简洁且不易出错
  • 适用场景:数组遍历、对象属性遍历等

基础示例

<?php
// 基础的 foreach 循环
echo "=== 基础 foreach 循环 ===<br>";

// 简单索引数组
$fruits = ['苹果', '香蕉', '橙子', '葡萄'];
foreach ($fruits as $fruit) {
    echo "水果: $fruit<br>";
}

// 关联数组
echo "<br>=== 关联数组遍历 ===<br>";
$student = [
    'name' => '张三',
    'age' => 20,
    'major' => '计算机科学',
    'gpa' => 3.8
];

foreach ($student as $key => $value) {
    echo "$key: $value<br>";
}

// 多维数组
echo "<br>=== 多维数组遍历 ===<br>";
$students = [
    [
        'name' => '张三',
        'scores' => ['数学' => 85, '英语' => 92, '编程' => 95]
    ],
    [
        'name' => '李四',
        'scores' => ['数学' => 78, '英语' => 88, '编程' => 82]
    ]
];

foreach ($students as $index => $student) {
    echo "学生 " . ($index + 1) . ": {$student['name']}<br>";
    foreach ($student['scores'] as $subject => $score) {
        echo "  $subject: $score 分<br>";
    }
    echo "<br>";
}

// 数组修改(引用传递)
echo "<br>=== 数组修改 ===<br>";
$numbers = [1, 2, 3, 4, 5];
echo "原数组: " . implode(', ', $numbers) . "<br>";

foreach ($numbers as &$value) {
    $value = $value * 2;
}
unset($value); // 解除引用

echo "修改后数组: " . implode(', ', $numbers) . "<br>";
?>

实际应用示例

<?php
// 1. 电商购物车处理
echo "=== 购物车价格计算 ===<br>";

$cartItems = [
    ['name' => 'iPhone 14', 'price' => 6999, 'quantity' => 1],
    ['name' => 'AirPods', 'price' => 1299, 'quantity' => 2],
    ['name' => '手机壳', 'price' => 99, 'quantity' => 3]
];

$subtotal = 0;
$itemCount = 0;

foreach ($cartItems as $item) {
    $itemTotal = $item['price'] * $item['quantity'];
    $subtotal += $itemTotal;
    $itemCount += $item['quantity'];

    echo "{$item['name']}: {$item['quantity']} × ¥{$item['price']} = ¥$itemTotal<br>";
}

$tax = $subtotal * 0.1; // 10% 税费
$shipping = ($subtotal >= 100) ? 0 : 10; // 满100免运费
$total = $subtotal + $tax + $shipping;

echo "<br>商品小计: ¥$subtotal<br>";
echo "税费 (10%): ¥$tax<br>";
echo "运费: ¥$shipping<br>";
echo "总计: ¥$total<br>";
echo "商品数量: $itemCount 件<br>";

// 2. 配置文件处理
echo "<br><br>=== 配置文件处理 ===<br>";
$config = [
    'database' => [
        'host' => 'localhost',
        'port' => 3306,
        'username' => 'admin'
    ],
    'app' => [
        'name' => 'MyApp',
        'version' => '1.0.0',
        'debug' => true
    ]
];

foreach ($config as $section => $settings) {
    echo "配置段: [$section]<br>";
    if (is_array($settings)) {
        foreach ($settings as $key => $value) {
            echo "  $key: $value<br>";
        }
    } else {
        echo "  $settings<br>";
    }
    echo "<br>";
}
?>

循环控制

break 语句

break 用于立即跳出当前循环:

<?php
// break 示例
echo "=== break 语句示例 ===<br>";

for ($i = 1; $i <= 10; $i++) {
    if ($i === 6) {
        echo "遇到 $i,跳出循环<br>";
        break;
    }
    echo "$i ";
}
// 输出: 1 2 3 4 5

// 查找数组中的特定元素
echo "<br><br>=== 查找特定元素 ===<br>";
$numbers = [10, 23, 45, 67, 89, 12, 34];
$target = 67;
$foundIndex = -1;

foreach ($numbers as $index => $number) {
    echo "检查索引 $index: 值 $number<br>";
    if ($number === $target) {
        $foundIndex = $index;
        echo "找到目标值 $target 在索引 $index,停止搜索<br>";
        break;
    }
}

if ($foundIndex !== -1) {
    echo "目标值 $target 的位置: $foundIndex<br>";
} else {
    echo "未找到目标值 $target<br>";
}
?>

continue 语句

continue 用于跳过当前循环的剩余代码,开始下一次循环:

<?php
// continue 示例
echo "=== continue 语句示例 ===<br>";

for ($i = 1; $i <= 10; $i++) {
    if ($i % 2 === 0) {
        continue; // 跳过偶数
    }
    echo "$i "; // 只输出奇数
}
// 输出: 1 3 5 7 9

// 过滤数组中的空值
echo "<br><br>=== 过滤空值 ===<br>";
$data = ['apple', '', 'banana', null, 'cherry', false, 'date'];
$filteredData = [];

foreach ($data as $index => $value) {
    if (empty($value)) {
        echo "索引 $index: 空值,跳过<br>";
        continue;
    }
    $filteredData[] = $value;
    echo "索引 $index: 保留值 '$value'<br>";
}

echo "<br>过滤后的数组: " . implode(', ', $filteredData) . "<br>";
?>

循环最佳实践

1. 选择合适的循环类型

<?php
// 什么时候使用哪种循环

// ✅ 推荐:已知循环次数使用 for
echo "=== 使用 for 循环的情况 ===<br>";
for ($i = 0; $i < 10; $i++) {
    echo "处理第 " . ($i + 1) . " 个项目<br>";
}

// ✅ 推荐:未知循环次数,只知道条件使用 while
echo "<br>=== 使用 while 循环的情况 ===<br>";
$remaining = 100;
while ($remaining > 0) {
    $consumed = rand(10, 30);
    $remaining = max(0, $remaining - $consumed);
    echo "消耗 $consumed,剩余 $remaining<br>";
}

// ✅ 推荐:必须至少执行一次使用 do-while
echo "<br>=== 使用 do-while 循环的情况 ===<br>";
$temperature = 25;
do {
    echo "当前温度: $temperature°C<br>";
    $temperature += rand(-2, 3);
} while ($temperature < 30);

// ✅ 推荐:数组遍历使用 foreach
echo "<br>=== 使用 foreach 循环的情况 ===<br>";
$users = ['Alice', 'Bob', 'Charlie'];
foreach ($users as $index => $user) {
    echo "用户 " . ($index + 1) . ": $user<br>";
}
?>

2. 性能优化建议

<?php
// 循环性能优化

// ✅ 推荐:将函数调用结果缓存到变量
echo "=== 性能优化示例 ===<br>";
$array = range(1, 1000);

// 优化前:每次循环都调用 count()
$start = microtime(true);
for ($i = 0; $i < count($array); $i++) {
    // 处理数组元素
}
$slowTime = microtime(true) - $start;

// 优化后:缓存 count() 结果
$start = microtime(true);
$count = count($array);
for ($i = 0; $i < $count; $i++) {
    // 处理数组元素
}
$fastTime = microtime(true) - $start;

echo "优化前时间: " . number_format($slowTime * 1000, 4) . "ms<br>";
echo "优化后时间: " . number_format($fastTime * 1000, 4) . "ms<br>";
?>

常见错误和解决方案

1. 无限循环

<?php
// 常见的无限循环问题

// ❌ 错误:忘记更新循环变量
// $i = 0;
// while ($i < 10) {
//     echo $i; // $i 永远不会增加,无限循环
// }

// ✅ 正确:记得更新循环变量
$i = 0;
while ($i < 10) {
    echo $i . " ";
    $i++; // 更新循环变量
}
?>

2. foreach 中的引用问题

<?php
// foreach 引用问题

$array = [1, 2, 3, 4, 5];

// ✅ 正确:使用引用后及时解除
foreach ($array as &$value) {
    $value = $value * 2;
}
unset($value); // 解除引用

echo "处理后的数组: " . implode(', ', $array) . "<br>";
?>

练习题

基础练习

  1. 数字求和

    <?php
    // 练习:计算1到100的和
    $sum = 0;
    
    // 使用 for 循环计算1到100的和
    for ($i = 1; $i <= 100; $i++) {
        $sum += $i;
    }
    
    echo "1到100的和是: $sum";
    ?>
    
  2. 数组元素遍历

    <?php
    // 练习:遍历数组并计算平均值
    $numbers = [85, 92, 78, 95, 88, 76, 89, 94];
    $total = 0;
    
    foreach ($numbers as $score) {
        $total += $score;
    }
    $average = $total / count($numbers);
    
    echo "平均分: " . round($average, 2);
    ?>
    
  3. 九九乘法表

    <?php
    // 练习:使用嵌套循环生成九九乘法表
    echo "<table border='1'>";
    
    for ($i = 1; $i <= 9; $i++) {
        echo "<tr>";
        for ($j = 1; $j <= 9; $j++) {
            $product = $i * $j;
            echo "<td>$i × $j = $product</td>";
        }
        echo "</tr>";
    }
    
    echo "</table>";
    ?>
    

进阶练习

  1. 质数生成器

    <?php
    // 练习:生成指定范围内的所有质数
    function generatePrimes($start, $end) {
        $primes = [];
    
        for ($number = $start; $number <= $end; $number++) {
            if ($number < 2) continue;
    
            $isPrime = true;
            for ($divisor = 2; $divisor * $divisor <= $number; $divisor++) {
                if ($number % $divisor == 0) {
                    $isPrime = false;
                    break;
                }
            }
    
            if ($isPrime) {
                $primes[] = $number;
            }
        }
    
        return $primes;
    }
    
    $primes = generatePrimes(1, 100);
    echo "1-100之间的质数: " . implode(', ', $primes);
    ?>
    
  2. 斐波那契数列

    <?php
    // 练习:生成斐波那契数列
    function fibonacci($n) {
        $sequence = [0, 1];
    
        for ($i = 2; $i < $n; $i++) {
            $sequence[$i] = $sequence[$i-1] + $sequence[$i-2];
        }
    
        return $sequence;
    }
    
    $fib = fibonacci(10);
    echo "斐波那契数列: " . implode(', ', $fib);
    ?>
    

总结

循环语句是PHP编程中最重要的控制结构之一,掌握好循环对于编写高效、简洁的代码至关重要。以下是关键要点:

核心概念

  1. for 循环:适用于已知循环次数的场景
  2. while 循环:适用于条件控制的场景
  3. do-while 循环:至少执行一次的后测试循环
  4. foreach 循环:专门用于数组遍历

选择建议

  • 固定次数:使用 for 循环
  • 条件控制:使用 while 循环
  • 至少一次:使用 do-while 循环
  • 数组遍历:使用 foreach 循环

最佳实践

  1. 选择合适的循环类型
  2. 避免无限循环
  3. 注意循环性能优化
  4. 使用有意义的变量名
  5. 及时解除引用
  6. 为复杂循环添加注释

常见陷阱

  1. 忘记更新循环变量导致无限循环
  2. 在循环中修改数组结构
  3. foreach 中的引用问题
  4. 循环变量的作用域问题

通过大量的练习和实际应用,您将能够熟练运用各种循环结构来解决复杂的编程问题。循环是程序设计中最重要的概念之一,掌握好它将大大提高您的编程能力。