PHP 循环 - For 循环详解

For 循环是 PHP 中最常用的循环结构之一,特别适用于已知循环次数的场景。它提供了简洁的语法来初始化变量、设置条件和更新变量。

循环结构概述

PHP 提供了多种循环结构来处理重复性任务,每种循环都有其特定的使用场景:

PHP 循环类型对比:

  • for - 在已知循环次数时使用
  • foreach - 专门用于遍历数组和对象
  • while - 在条件为真时重复执行
  • do...while - 至少执行一次,然后在条件为真时重复

选择循环类型的建议:

  • 当确切知道循环次数时,使用 for 循环
  • 当需要遍历数组或对象时,使用 foreach 循环
  • 当循环次数不确定但知道循环条件时,使用 while 循环
  • 当需要至少执行一次循环体时,使用 do...while 循环

For 循环

For 循环用于在预先知道脚本需要运行次数的情况。它将循环控制集中在一行代码中,使得代码更加简洁和易读。

基本语法

for (初始值; 条件; 增量) {
    // 要执行的代码
}

执行流程

  1. 执行初始化表达式(只在循环开始时执行一次)
  2. 检查条件表达式
  3. 如果条件为真,执行循环体内的代码
  4. 执行增量表达式
  5. 重复步骤2-4,直到条件为假

基础示例:数字输出

<?php
for ($i = 1; $i <= 5; $i++) {
    echo "数字是: " . $i . "<br>";
}
?>
输出:
数字是: 1
数字是: 2
数字是: 3
数字是: 4
数字是: 5

实际应用:生成表格

<?php
echo "<table border='1'>";
echo "<tr><th>数字</th><th>平方</th><th>立方</th></tr>";

for ($i = 1; $i <= 5; $i++) {
    $square = $i * $i;
    $cube = $i * $i * $i;

    echo "<tr>";
    echo "<td>$i</td>";
    echo "<td>$square</td>";
    echo "<td>$cube</td>";
    echo "</tr>";
}

echo "</table>";
?>

For 循环的变体

多变量初始化

同时初始化多个变量

<?php
// 初始化多个变量
for ($i = 0, $j = 10; $i < 5; $i++, $j--) {
    echo "i = $i, j = $j<br>";
}
?>
输出:
i = 0, j = 10
i = 1, j = 9
i = 2, j = 8
i = 3, j = 7
i = 4, j = 6

空表达式

省略部分表达式

<?php
// 省略初始化表达式
$i = 1;
for (; $i <= 3; $i++) {
    echo "数字: $i<br>";
}

echo "<br>";

// 省略增量表达式
for ($j = 1; $j <= 3;) {
    echo "数字: $j<br>";
    $j++; // 在循环体内更新
}
?>

无限循环

使用 for 创建无限循环

<?php
// 无限循环(实际使用时需要退出条件)
for (;;) {
    // 需要 break 语句来退出
    break; // 这里立即退出,避免真正无限循环
}

// 带退出条件的无限循环
$counter = 0;
for (;;) {
    $counter++;
    echo "循环执行: $counter<br>";

    if ($counter >= 3) {
        break;
    }
}
?>

Foreach 循环

Foreach 循环是专门为遍历数组和对象设计的循环结构,它提供了简洁的语法来访问数组的每个元素。

基本语法

// 只获取值
foreach ($array as $value) {
    // 使用 $value
}

// 获取键和值
foreach ($array as $key => $value) {
    // 使用 $key 和 $value
}

基础示例:遍历数组

<?php
// 索引数组
$colors = array("red", "green", "blue");

foreach ($colors as $color) {
    echo "颜色: $color<br>";
}

echo "<br>";

// 关联数组
$age = array("Peter" => 35, "Ben" => 37, "Joe" => 43);

foreach ($age as $name => $ageValue) {
    echo "$name 的年龄是 $ageValue<br>";
}
?>
输出:
颜色: red
颜色: green
颜色: blue

Peter 的年龄是 35
Ben 的年龄是 37
Joe 的年龄是 43

Foreach 循环的高级用法

引用传递

修改原数组元素

<?php
$numbers = [1, 2, 3, 4, 5];

echo "原数组: ";
print_r($numbers);
echo "<br>";

// 使用引用修改原数组
foreach ($numbers as &$number) {
    $number = $number * 2;
}

echo "修改后: ";
print_r($numbers);

// 重要:使用后取消引用
unset($number);
?>

多维数组遍历

嵌套 foreach 循环

<?php
$students = [
    "class1" => ["Alice", "Bob", "Charlie"],
    "class2" => ["David", "Eva", "Frank"],
    "class3" => ["Grace", "Henry", "Ivy"]
];

foreach ($students as $className => $studentList) {
    echo "<h3>$className</h3>";
    echo "<ul>";

    foreach ($studentList as $index => $student) {
        echo "<li>学生 " . ($index + 1) . ": $student</li>";
    }

    echo "</ul>";
}
?>

使用 list() 解构

解构嵌套数组

<?php
$people = [
    [1, "Alice", "alice@example.com"],
    [2, "Bob", "bob@example.com"],
    [3, "Charlie", "charlie@example.com"]
];

foreach ($people as list($id, $name, $email)) {
    echo "ID: $id, 姓名: $name, 邮箱: $email<br>";
}

// PHP 7.1+ 使用方括号语法
foreach ($people as [$id, $name, $email]) {
    echo "ID: $id, 姓名: $name, 邮箱: $email<br>";
}
?>

循环控制语句

在 for 和 foreach 循环中,可以使用 breakcontinue 来控制循环流程。

break 语句

提前终止循环

<?php
// for 循环中的 break
for ($i = 1; $i <= 10; $i++) {
    if ($i == 5) {
        echo "遇到 5,终止循环<br>";
        break;
    }
    echo "当前数字: $i<br>";
}

echo "<br>";

// foreach 循环中的 break
$fruits = ["apple", "banana", "cherry", "date", "elderberry"];
foreach ($fruits as $fruit) {
    if ($fruit == "cherry") {
        echo "找到 cherry,停止遍历<br>";
        break;
    }
    echo "水果: $fruit<br>";
}
?>

continue 语句

跳过当前迭代

<?php
// for 循环中的 continue
for ($i = 1; $i <= 5; $i++) {
    if ($i == 3) {
        echo "跳过数字 3<br>";
        continue;
    }
    echo "当前数字: $i<br>";
}

echo "<br>";

// foreach 循环中的 continue
$numbers = [1, 2, 3, 4, 5, 6];
foreach ($numbers as $number) {
    if ($number % 2 == 0) {
        continue; // 跳过偶数
    }
    echo "奇数: $number<br>";
}
?>

break 和 continue 的层级控制

多层循环控制

<?php
// 嵌套循环中的 break
for ($i = 1; $i <= 3; $i++) {
    echo "外层循环: $i<br>";

    for ($j = 1; $j <= 3; $j++) {
        if ($i == 2 && $j == 2) {
            echo "跳出外层循环<br>";
            break 2; // 跳出2层循环
        }
        echo "内层循环: $j<br>";
    }
}

echo "<br>";

// 嵌套循环中的 continue
for ($i = 1; $i <= 3; $i++) {
    for ($j = 1; $j <= 3; $j++) {
        if ($j == 2) {
            continue 2; // 继续外层循环的下一次迭代
        }
        echo "i=$i, j=$j<br>";
    }
}
?>

实际应用场景

数据处理:数组操作

数组过滤和转换

<?php
// 使用 for 循环处理数组
$numbers = [10, 20, 30, 40, 50];
$squaredNumbers = [];

for ($i = 0; $i < count($numbers); $i++) {
    $squaredNumbers[] = $numbers[$i] * $numbers[$i];
}

echo "平方数: " . implode(', ', $squaredNumbers) . "<br>";

// 使用 foreach 处理关联数组
$products = [
    "laptop" => 1200,
    "mouse" => 25,
    "keyboard" => 80,
    "monitor" => 300
];

$expensiveProducts = [];
foreach ($products as $product => $price) {
    if ($price > 100) {
        $expensiveProducts[$product] = $price;
    }
}

echo "高价产品: <br>";
foreach ($expensiveProducts as $product => $price) {
    echo "- $product: $$price<br>";
}
?>

内容生成:动态HTML

生成动态内容

<?php
// 生成导航菜单
$menuItems = [
    "首页" => "/",
    "产品" => "/products",
    "关于我们" => "/about",
    "服务" => "/services",
    "联系我们" => "/contact"
];

echo "<nav><ul>";
foreach ($menuItems as $text => $url) {
    $active = ($url == "/products") ? ' class="active"' : ''; // 模拟当前页面
    echo "<li><a href='$url'$active>$text</a></li>";
}
echo "</ul></nav>";

echo "<br>";

// 生成日历网格
echo "<div class='calendar'>";
echo "<div class='week'>";
for ($day = 1; $day <= 31; $day++) {
    echo "<div class='day'>$day</div>";

    // 每周换行
    if ($day % 7 == 0) {
        echo "</div><div class='week'>";
    }
}
echo "</div></div>";
?>

算法实现:数学计算

数学算法示例

<?php
// 计算阶乘
function factorial($n) {
    $result = 1;
    for ($i = 1; $i <= $n; $i++) {
        $result *= $i;
    }
    return $result;
}

echo "5的阶乘: " . factorial(5) . "<br>";

// 生成斐波那契数列
function fibonacci($count) {
    $fib = [0, 1];

    for ($i = 2; $i < $count; $i++) {
        $fib[$i] = $fib[$i-1] + $fib[$i-2];
    }

    return array_slice($fib, 0, $count);
}

echo "斐波那契数列 (前10个): " . implode(', ', fibonacci(10)) . "<br>";

// 查找质数
function findPrimes($limit) {
    $primes = [];

    for ($num = 2; $num <= $limit; $num++) {
        $isPrime = true;

        for ($i = 2; $i <= sqrt($num); $i++) {
            if ($num % $i == 0) {
                $isPrime = false;
                break;
            }
        }

        if ($isPrime) {
            $primes[] = $num;
        }
    }

    return $primes;
}

echo "100以内的质数: " . implode(', ', findPrimes(100)) . "<br>";
?>

性能优化和最佳实践

循环性能优化

减少循环内的计算

<?php
// 优化前:在循环条件中重复计算
$data = [1, 2, 3, 4, 5];
for ($i = 0; $i < count($data); $i++) { // count() 在每次迭代都执行
    echo $data[$i] . "<br>";
}

echo "<br>";

// 优化后:预先计算循环次数
$data = [1, 2, 3, 4, 5];
$count = count($data); // 预先计算
for ($i = 0; $i < $count; $i++) {
    echo $data[$i] . "<br>";
}

echo "<br>";

// 对于大型数组,foreach 通常比 for 更快
$largeArray = range(1, 1000);

// 使用 foreach(推荐)
foreach ($largeArray as $value) {
    // 处理数据
}

// 使用 for
for ($i = 0, $count = count($largeArray); $i < $count; $i++) {
    // 处理数据
}
?>

选择正确的循环类型

循环选择指南:

  • 使用 for 循环:当确切知道循环次数时
  • 使用 foreach 循环:当需要遍历数组或对象时
  • 避免在 foreach 中修改数组结构:这可能导致意外行为
  • 使用引用时记得 unset:避免后续的变量污染
  • 考虑使用 array_map/filter:对于简单的数组转换,函数式方法可能更清晰

避免常见错误

常见错误和解决方案

<?php
// 错误1:在循环内修改数组长度
$numbers = [1, 2, 3, 4, 5];
/*
for ($i = 0; $i < count($numbers); $i++) {
    if ($numbers[$i] == 3) {
        unset($numbers[$i]); // 这会改变数组长度和索引
    }
}
*/

// 正确做法:从后往前遍历或使用新数组
for ($i = count($numbers) - 1; $i >= 0; $i--) {
    if ($numbers[$i] == 3) {
        unset($numbers[$i]);
    }
}

// 错误2:在 foreach 中使用引用后不 unset
$items = [1, 2, 3];
foreach ($items as &$item) {
    $item *= 2;
}
// unset($item); // 重要:使用后取消引用

// 错误3:在循环中执行不必要的数据库查询或文件操作
// 应该将这些操作移到循环外或进行批量处理
?>

PHP 7/8 新特性

PHP 7.1 的方括号列表

新的解构语法

<?php
// PHP 7.1+ 方括号列表语法
$coordinates = [
    [1, 2],
    [3, 4],
    [5, 6]
];

foreach ($coordinates as [$x, $y]) {
    echo "坐标: ($x, $y)<br>";
}

// 传统方式(PHP 7.1 之前)
foreach ($coordinates as $coord) {
    list($x, $y) = $coord;
    echo "坐标: ($x, $y)<br>";
}
?>

PHP 8 的 match 表达式与循环

在循环中使用 match

<?php
// PHP 8+ match 表达式在循环中的应用
$scores = [85, 92, 78, 45, 60];

foreach ($scores as $index => $score) {
    $grade = match(true) {
        $score >= 90 => 'A',
        $score >= 80 => 'B',
        $score >= 70 => 'C',
        $score >= 60 => 'D',
        default => 'F'
    };

    echo "学生 " . ($index + 1) . ": 分数 $score, 等级 $grade<br>";
}
?>

总结

  • For 循环适用于已知循环次数的场景,语法为 for (初始值; 条件; 增量)
  • Foreach 循环专门用于遍历数组和对象,语法简洁高效
  • 使用 break 终止循环,使用 continue 跳过当前迭代
  • 在嵌套循环中,可以使用数字参数指定要控制循环层级
  • Foreach 中使用引用时,记得使用后 unset 引用变量
  • 优化循环性能:预先计算循环次数,减少循环内的重复计算
  • 根据具体场景选择合适的循环类型,提高代码可读性和性能
  • PHP 7.1+ 支持方括号列表语法,PHP 8 的 match 表达式可以与循环结合使用