for: counting loops
When you know how many times something should happen, a for loop keeps everything about the counting in one line:
<?php
for ($i = 1; $i <= 5; $i++) {
echo "Step $i\n";
}Step 1
Step 2
Step 3
Step 4
Step 5The brackets hold three parts separated by semicolons:
- Start:
$i = 1runs once, before the first pass. - Condition:
$i <= 5is checked before every pass; the loop stops when it is false. - Step:
$i++runs after every pass.
This is the same as the while loop from the previous lesson, with the setup and the update moved into the header where they are hard to forget. The step can be anything, such as counting down or in fives:
<?php
for ($t = 10; $t >= 0; $t -= 5) {
echo "T minus $t\n";
}
for ($row = 1; $row <= 3; $row++) {
echo "7 x $row = " . 7 * $row . "\n";
}T minus 10
T minus 5
T minus 0
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21You can loop over an indexed array with for and count(), but there is a better tool for that.
foreach: visiting every element
foreach goes through an array from the first element to the last, giving you each value in turn. No counter, no count(), no risk of an off-by-one mistake:
<?php
$products = ["Mechanical Keyboard", "Ceramic Mug Set", "Water Bottle"];
foreach ($products as $product) {
echo "- $product\n";
}- Mechanical Keyboard
- Ceramic Mug Set
- Water BottleKeys and values
Arrays in PHP can have meaningful keys, such as product names mapped to prices (arrays get their own section). The key => value form gives you both:
<?php
$prices = [
"Mechanical Keyboard" => 89.5,
"Ceramic Mug Set" => 18.75,
"Water Bottle" => 12.0,
];
$total = 0;
foreach ($prices as $name => $price) {
printf("%-20s %6.2f\n", $name, $price);
$total += $price;
}
printf("%-20s %6.2f\n", "Total", $total);Mechanical Keyboard 89.50
Ceramic Mug Set 18.75
Water Bottle 12.00
Total 120.25For an ordinary list, the key is the position, starting at 0. Add one when showing it to people:
<?php
$steps = ["Add to cart", "Enter address", "Pay"];
foreach ($steps as $index => $step) {
echo ($index + 1) . ". $step\n";
}1. Add to cart
2. Enter address
3. PayUnpacking rows
When each element is itself a small array, you can unpack it straight into variables with square brackets:
<?php
$orders = [
[1001, "Asha", 108.25],
[1002, "Liam", 24.99],
];
foreach ($orders as [$id, $customer, $amount]) {
echo "Order $id for $customer: $amount\n";
}Order 1001 for Asha: 108.25
Order 1002 for Liam: 24.99Changing elements while looping
foreach gives you a copy of each value, so assigning to $price inside the loop does not change the array. There are two ways to change elements in place. The clearest is to write back through the key:
<?php
$prices = ["Keyboard" => 89.5, "Mug" => 18.75];
foreach ($prices as $name => $price) {
$prices[$name] = round($price * 1.18, 2); // add 18% tax
}
print_r($prices);Array
(
[Keyboard] => 105.61
[Mug] => 22.13
)The other is a reference, written &$value, which makes the loop variable an alias for the element. It works, but it has a trap: after the loop, $value still points at the last element. Always unset() it straight away:
<?php
$quantities = [1, 2, 3];
foreach ($quantities as &$quantity) {
$quantity *= 10;
}
unset($quantity); // break the link to the last element
print_r($quantities);Array
(
[0] => 10
[1] => 20
[2] => 30
)Without that unset(), a later foreach ($quantities as $quantity) would write each value into the last element in turn and corrupt the array. Many teams avoid references in loops entirely and use the key, or array_map() from array_map, array_filter and array_reduce.
break and continue
break and continue work in for and foreach exactly as in while: leave the loop, or skip to the next element.
<?php
$stock = ["Keyboard" => 60, "Puzzle" => 0, "Mug" => 120, "Bands" => 0];
foreach ($stock as $name => $units) {
if ($units > 0) {
continue;
}
echo "$name is sold out\n";
}Puzzle is sold out
Bands is sold outAlternative syntax for templates
In HTML templates, foreach and for can use a colon and endforeach; / endfor;, which is easier to match up between tags:
<ul>
<?php foreach ($products as $product): ?>
<li><?= htmlspecialchars($product) ?></li>
<?php endforeach; ?>
</ul>Common mistakes
- Using for with count() on arrays whose keys are not 0, 1, 2... foreach works for every array.
- Expecting assignment to the loop variable to change the array. Use the key or a reference.
- Forgetting unset() after a by-reference foreach.
- Changing an array's size inside a for loop that uses
count()in its condition.
Exercise
Given the stock list ["Keyboard" => 60, "Headphones" => 25, "Desk Mat" => 40, "Puzzle" => 0], use one foreach to print each product with "low" next to anything under 30, and count how many products are low.
Show one possible answer
<?php
$stock = ["Keyboard" => 60, "Headphones" => 25, "Desk Mat" => 40, "Puzzle" => 0];
$low = 0;
foreach ($stock as $name => $units) {
$flag = "";
if ($units < 30) {
$flag = " (low)";
$low++;
}
echo "$name: $units$flag\n";
}
echo "$low products are low\n";Keyboard: 60
Headphones: 25 (low)
Desk Mat: 40
Puzzle: 0 (low)
2 products are lowKey points
- for (start; condition; step) is ideal when you know how many passes you need.
- foreach ($items as $item) visits every element of an array; foreach ($items as $key => $value) also gives the key.
- foreach works on a copy; to change elements in place use &$value and unset($value) afterwards, or write back with the key.
- list-style destructuring, foreach ($rows as [$name, $price]), unpacks each element into variables.