for and foreach Loops

for loops count; foreach loops walk through arrays and other collections. Between them they cover most repetition in PHP — foreach in particular is the loop you'll write most often, because so much PHP code processes arrays of rows, items and records.

The for loop

A for loop puts initialisation, condition and update on one line:

PHP
<?php

for ($i = 1; $i <= 5; $i++) {
    echo "Pass $i\n";
}
Output
Pass 1
Pass 2
Pass 3
Pass 4
Pass 5

The first part runs once, the condition is checked before every pass, and the update runs after every pass. Other step sizes work too:

PHP
<?php

for ($i = 10; $i > 0; $i -= 3) {
    echo $i, " ";
}
echo "\n";

for ($i = 1; $i <= 1000; $i *= 10) {
    echo $i, " ";
}
echo "\n";
Output
10 7 4 1
1 10 100 1000

foreach over a list

foreach visits every element of an array in order. No index bookkeeping, no off-by-one errors:

PHP
<?php

$planets = ["Mercury", "Venus", "Earth", "Mars"];

foreach ($planets as $planet) {
    echo strtoupper($planet), "\n";
}

foreach ($planets as $index => $planet) {
    echo $index + 1, ". $planet\n";
}
Output
MERCURY
VENUS
EARTH
MARS
1. Mercury
2. Venus
3. Earth
4. Mars

foreach over keys and values

With an associative array (lesson 22), $key => $value gives you both:

PHP
<?php

$prices = ["coffee" => 3.20, "tea" => 2.50, "cake" => 4.75];

foreach ($prices as $item => $price) {
    printf("%-7s %5.2f\n", $item, $price);
}
Output
coffee   3.20
tea      2.50
cake     4.75

Changing elements while looping

foreach works on a copy of each value, so assigning to the loop variable doesn't change the array. Either write back using the key, or loop by reference with &:

PHP
<?php

$prices = [10, 20, 30];

foreach ($prices as $key => $price) {
    $prices[$key] = $price * 2;
}
echo implode(", ", $prices), "\n";

foreach ($prices as &$price) {
    $price += 1;
}
unset($price);     // important: break the reference after the loop
echo implode(", ", $prices), "\n";
Output
20, 40, 60
21, 41, 61

After a by-reference loop, $price is still a reference to the last element. Forgetting unset($price) leads to a famous bug where a later loop silently overwrites that element. Often the cleanest option is to build a new array with array_map (lesson 23) instead.

Nested loops

PHP
<?php

for ($row = 1; $row <= 4; $row++) {
    for ($col = 1; $col <= 4; $col++) {
        printf("%4d", $row * $col);
    }
    echo "\n";
}
Output
   1   2   3   4
   2   4   6   8
   3   6   9  12
   4   8  12  16

break and continue with levels

In nested loops, break and continue accept a number saying how many levels to affect — break 2 leaves both loops:

PHP
<?php

$grid = [
    [4, 8, 15],
    [16, 23, 42],
    [7, 9, 11],
];

foreach ($grid as $r => $row) {
    foreach ($row as $c => $value) {
        if ($value === 23) {
            echo "Found 23 at row $r, column $c\n";
            break 2;
        }
    }
}
echo "Search finished\n";
Output
Found 23 at row 1, column 1
Search finished

Ranges

range() creates an array of numbers or letters, handy for quick loops:

PHP
<?php

foreach (range(1, 5) as $n) {
    echo $n * $n, " ";
}
echo "\n";
echo implode("", range('a', 'e')), "\n";
echo implode(" ", range(0, 100, 25)), "\n";
echo array_sum(range(1, 100)), "\n";
Output
1 4 9 16 25
abcde
0 25 50 75 100
5050

Loops in templates

In HTML templates, foreach with the alternative syntax keeps markup readable:

PHP menu.php
<?php
$menu = ['Home' => '/', 'Blog' => '/blog', 'About' => '/about'];
$current = '/blog';
?>
<nav>
<?php foreach ($menu as $label => $url): ?>
  <a href="<?= $url ?>"<?= $url === $current ? ' class="active"' : '' ?>><?= $label ?></a>
<?php endforeach; ?>
</nav>
HTTP
GET /menu.php
Responses
> GET /menu.php
<nav>
  <a href="/">Home</a>
  <a href="/blog" class="active">Blog</a>
  <a href="/about">About</a>
</nav>

Choosing a loop

LoopUse it when
foreachYou want every element of an array or iterable. The default choice.
forYou're counting, or need a custom step.
whileYou repeat until something changes and don't know how many passes it'll take.
do-whileThe body must run at least once.

Try it yourself

Print a right-angled triangle of stars, then change it to print numbers or count down.

Try it yourself · main.php
Edit the code, copy it into main.php, then run it with php main.php (PHP 8.5). How to install PHP
Output
*
**
***
****
*****
-----