Lesson 5 • Beginner
Loops 🔁
By the end of this lesson you'll repeat work without copy-pasting — counting with for, waiting on a condition with while and do-while, and walking through arrays with foreach, the loop you'll reach for most in real PHP.
What You'll Learn in This Lesson
- Count a known number of times with a for loop
- Repeat until a condition changes with while and do-while
- Walk an array with foreach ($arr as $value)
- Read keys and values with foreach ($arr as $key => $value)
- Steer a loop with break and continue (including break 2)
- Write loops cleanly in templates with endforeach / endfor
if conditions and comparisons like <= and ===, since loops lean on them. PHP has no in-browser runner here, so every example is genuine PHP you run yourself: paste it into the free onecompiler.com/php, or install PHP and run php file.php. The Output panel under each example shows exactly what to expect.for loop is the timer: "spin exactly 12 times." A while loop is the water sensor: "keep filling while the drum isn't full." A do-while always does one wash before checking if another is needed. And foreach is going through the laundry basket and handling every single item in it, one by one.1️⃣ The for Loop — Counting
A loop runs the same block of code over and over so you don't have to copy-paste it. The for loop is the one to use when you know how many times to repeat. Its header has three parts inside the brackets, separated by semicolons: a start value, a condition checked before each pass, and a step that runs after each pass. The $i++ step means "add 1 to $i".
<?php
// A FOR loop is for when you know HOW MANY times to repeat.
// It has three parts inside ( ) separated by semicolons:
// 1) start: $i = 1 — runs once, before the loop
// 2) check: $i <= 5 — tested before every pass; loop runs while true
// 3) step: $i++ — runs after every pass ($i++ means "add 1 to $i")
for ($i = 1; $i <= 5; $i++) {
echo "Count: $i\n"; // PHP swaps $i for its value inside "double quotes"
}
echo "Done!\n"; // runs once, AFTER the loop finishes
?>Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Done!Read the header as: start at 1, keep going while $i <= 5, and add 1 each time. When $i hits 6 the condition is false, the loop ends, and the code after it runs once.
2️⃣ The while Loop — Repeat Until Done
Sometimes you don't know the count in advance — you just want to keep going until something happens. That's the while loop: it checks a condition before each pass and repeats as long as it's true. The golden rule: something inside the loop must move you toward the condition becoming false, or the loop never ends.
<?php
// A WHILE loop repeats as long as a condition stays true.
// Use it when you DON'T know the count up front — here we stop when a
// total passes 100. You must change something inside the loop, or it
// would run forever.
$total = 0; // start at zero
$day = 0; // counts how many days we added
while ($total < 100) { // keep going WHILE total is under 100
$day++; // move to the next day (add 1)
$total += 20; // $total += 20 is short for $total = $total + 20
echo "Day $day: total is $total\n";
}
echo "Reached the goal in $day days.\n";
?>Day 1: total is 20
Day 2: total is 40
Day 3: total is 60
Day 4: total is 80
Day 5: total is 100
Reached the goal in 5 days.Here $total += 20 grows the total every pass, so the condition $total < 100 eventually turns false and the loop stops. Take that line out and you'd have an infinite loop.
3️⃣ The do-while Loop — Run At Least Once
A do-while loop is a while loop flipped upside down: it runs the body first, then checks the condition at the bottom. Because of that, the body always runs at least once — even if the condition was false from the very start. It's the right choice whenever the work must happen one time before you decide whether to repeat (think "show the menu, then ask if they want it again").
<?php
// A DO-WHILE loop runs the body FIRST, then checks the condition.
// So it always runs AT LEAST ONCE — even if the condition is false to begin
// with. Perfect for "show a menu, then ask again" style code.
$count = 10;
do {
echo "Body ran with count = $count\n"; // this prints once...
$count++;
} while ($count < 5); // ...even though 10 < 5 is false
echo "Notice the body ran once despite the false condition.\n";
?>Body ran with count = 10
Notice the body ran once despite the false condition.4️⃣ foreach — Walking an Array
This is the loop you'll use most in PHP. An array is an ordered list of values, and foreach hands you each one in turn — no counter, no index, no off-by-one mistakes. The simplest form is foreach ($arr as $value): on each pass, your variable (here $fruit) holds the next item.
<?php
// FOREACH is PHP's most-used loop — it walks through every item in an array.
// The simplest form gives you each VALUE in turn: foreach ($arr as $value)
$fruits = ["Apple", "Banana", "Cherry", "Date"];
foreach ($fruits as $fruit) { // $fruit holds one item each time round
echo "I like $fruit\n";
}
echo "That's " . count($fruits) . " fruits.\n"; // count() = how many items
?>I like Apple
I like Banana
I like Cherry
I like Date
That's 4 fruits.5️⃣ foreach with Keys — $key => $value
Every array item has a key (its label) as well as a value. In a plain list the keys are positions — 0, 1, 2… In an associative array the keys are names you chose, like "coffee". The form foreach ($arr as $key => $value) gives you both at once: the part before => is the key, the part after is the value.
<?php
// The KEY => VALUE form gives you BOTH the key and the value each pass.
// For a list, the key is the position (0, 1, 2...).
// For an associative array (named keys), the key is the name.
$prices = ["coffee" => 3.50, "muffin" => 2.00, "juice" => 4.25];
foreach ($prices as $item => $price) { // $item = key, $price = value
echo "$item costs \$$price\n"; // \$ prints a literal $ sign
}
// It works on a plain list too — here the key is the index:
$colours = ["red", "green", "blue"];
foreach ($colours as $index => $colour) {
echo "[$index] $colour\n";
}
?>coffee costs $3.5
muffin costs $2
juice costs $4.25
[0] red
[1] green
[2] blueNotice 3.50 printed as 3.5 — PHP drops a trailing zero when it shows a number. To force two decimals (real money) you'd use number_format($price, 2) or printf, which you'll see in the order example below.
6️⃣ break & continue — Steering the Loop
break leaves the loop completely — handy once you've found what you were looking for. continue skips just the rest of the current pass and jumps to the next one. When loops are nested (a loop inside a loop), you can add a number: break 2 breaks out of two loops at once, and continue 2 jumps to the next pass of the outer loop.
<?php
// BREAK stops the loop completely. CONTINUE skips the rest of THIS pass
// and jumps to the next one. Both are usually paired with an if.
echo "=== break: stop at the first match ===\n";
$numbers = [3, 7, 12, 5, 20];
foreach ($numbers as $num) {
if ($num > 10) {
echo "Found one over 10: $num — stopping.\n";
break; // leave the loop entirely
}
echo "Checked $num, too small.\n";
}
echo "\n=== continue: skip the even ones ===\n";
for ($i = 1; $i <= 6; $i++) {
if ($i % 2 === 0) { // % is remainder; even numbers give 0
continue; // skip the echo, go to next $i
}
echo "Odd: $i\n";
}
// LEVELS: break 2 / continue 2 act on the OUTER loop, not just the inner one.
echo "\n=== break 2: leave BOTH loops at once ===\n";
for ($row = 1; $row <= 3; $row++) {
for ($col = 1; $col <= 3; $col++) {
if ($row === 2 && $col === 2) {
echo "Hit ($row,$col) — break 2 leaves both loops.\n";
break 2; // not just the inner loop — both
}
echo "At ($row,$col)\n";
}
}
?>=== break: stop at the first match ===
Checked 3, too small.
Checked 7, too small.
Found one over 10: 12 — stopping.
=== continue: skip the even ones ===
Odd: 1
Odd: 3
Odd: 5
=== break 2: leave BOTH loops at once ===
At (1,1)
At (1,2)
At (1,3)
At (2,1)
Hit (2,2) — break 2 leaves both loops.Now you try. The script below counts down, so the condition and step are different from a normal count-up. Fill in each ___ using the 👉 hint, then run it and check it against the Output panel.
<?php
// 🎯 YOUR TURN — print a countdown from 5 down to 1, then "Lift off!".
// A countdown goes DOWNWARDS, so the step must SUBTRACT. Fill the blanks.
for ($i = 5; $i ___ 1; $i--) { // 👉 keep going while $i is >= 1 (use: >= )
echo ___; // 👉 echo the number then a newline, e.g. "$i\n"
}
echo "Lift off!\n";
// ✅ Expected output:
// 5
// 4
// 3
// 2
// 1
// Lift off!
?>5
4
3
2
1
Lift off!___ with >= and the second with "$i\n", then run it. You should see 5 down to 1, then "Lift off!".One more — this time practise the key => value form. Name the key and value variables so the echo already in the code lines up.
<?php
// 🎯 YOUR TURN — print each student and their score using KEY => VALUE.
// Fill the two blanks so PHP gives you both the name (key) and the mark (value).
$scores = ["Maya" => 88, "Owen" => 73, "Priya" => 95];
foreach ($scores as ___ => ___) { // 👉 first blank = the key, second = the value
echo "$name scored $score\n"; // 👉 so name your variables $name and $score
}
// ✅ Expected output:
// Maya scored 88
// Owen scored 73
// Priya scored 95
?>Maya scored 88
Owen scored 73
Priya scored 95$name and the second to $score so they match the echo line. Run it to see three names and scores.7️⃣ Alternative Syntax — endforeach & endfor
PHP lets you swap the curly braces { } for a colon and a matching end word: foreach (…): … endforeach; and for (…): … endfor; Both forms do exactly the same thing. This style shines when a loop is wrapped around HTML in a template, because a named endforeach; is far easier to pair up than a lone } buried among tags.
<?php
// ALTERNATIVE SYNTAX: instead of { } you can use a colon and an "end" word.
// This reads much better when you mix loops with HTML in a template, because
// the closing endforeach / endfor is clearer than a lonely }.
$users = ["Ada", "Linus", "Grace"];
?>
<ul>
<?php foreach ($users as $user): ?>
<li><?php echo $user; ?></li>
<?php endforeach; ?>
</ul>
<?php for ($n = 1; $n <= 3; $n++): ?>
<p>Row <?php echo $n; ?></p>
<?php endfor; ?><ul>
<li>Ada</li>
<li>Linus</li>
<li>Grace</li>
</ul>
<p>Row 1</p>
<p>Row 2</p>
<p>Row 3</p>8️⃣ Putting It Together — An Order Total
Here's the whole lesson in one realistic snippet: a foreach over a cart with named keys, a continue to skip out-of-stock items, and a running total. This is the exact shape of code you'd write to add up a real shopping basket.
<?php
// REAL-WORLD: total up an online order, skipping out-of-stock items.
// This combines foreach (key => value), continue, and a running total —
// the exact pattern you'll use on real shopping carts.
$cart = [
"Laptop" => 999.00,
"Mouse" => 25.50,
"Keyboard" => 0, // 0 means out of stock — we'll skip it
"Monitor" => 180.75,
];
$total = 0;
$lines = 0;
foreach ($cart as $product => $price) {
if ($price <= 0) {
echo "$product: out of stock (skipped)\n";
continue; // don't add it to the total
}
$total += $price;
$lines++;
printf("%-9s \$%.2f\n", $product, $price); // %-9s pads the name to 9 chars
}
echo "-------------------\n";
printf("Items: %d Total: \$%.2f\n", $lines, $total);
?>Laptop $999.00
Mouse $25.50
Keyboard: out of stock (skipped)
Monitor $180.75
-------------------
Items: 3 Total: $1205.25Common Errors (and the fix)
- The page hangs / "Maximum execution time exceeded" (infinite loop) — your loop's condition never becomes false. Almost always you forgot to change the variable it depends on: a
while ($i < 10)with no$i++inside runs forever. Make sure every loop body moves toward the condition being false. - Your array changed unexpectedly after a foreach (the reference trap) — using
foreach ($arr as &$value)makes$valuea live link to each element, and it still points at the last item after the loop. Reusing$valuethen overwrites that item. Fix: callunset($value);right after the loop. - Weird results from adding/removing items during a foreach —
foreachworks on a copy of the array's pointer, so changing the array mid-loop leads to skipped or repeated items. Build a new array (or collect changes and apply them after), rather than editing the one you're looping over. - Off-by-one: the loop runs one too many or one too few times — this is the
<vs<=mix-up.for ($i = 0; $i < 5; $i++)runs for 0,1,2,3,4 (five times); using<= 5would run six times. Decide whether you start at 0 or 1 and pick the matching comparison. - "Parse error: syntax error, unexpected 'endforeach'" — you opened the loop with a brace
{but tried to close it withendforeach;. Don't mix the two styles: either{ … }or: … endforeach;
Pro Tips
- 💡 Default to
foreachfor arrays. It can't go out of bounds and reads cleaner than aforwith an index. Save plainforfor when you truly need a counting number. - 💡 Break early once you've found it. Searching a list?
breakthe moment you have a match instead of scanning the rest — faster and clearer. - 💡 Use the alternative syntax in templates.
: … endforeach;is much easier to read inside HTML than a stray closing brace.
📋 Quick Reference — PHP Loops
| Syntax | Example | What It Does |
|---|---|---|
| for (a; b; c) { } | for ($i=0; $i<5; $i++) | Loop a known number of times |
| while (cond) { } | while ($x < 10) | Repeat while a condition is true |
| do { } while (cond); | do { … } while ($x<10); | Run once, then repeat while true |
| foreach ($a as $v) | foreach ($f as $fruit) | Walk each value of an array |
| foreach ($a as $k => $v) | foreach ($p as $name => $age) | Walk key and value together |
| break / break 2 | break 2; | Exit one (or N nested) loops |
| continue / continue 2 | continue; | Skip to the next iteration |
| : … endforeach; / endfor; | foreach (…): … endforeach; | Brace-free style for templates |
Frequently Asked Questions
Q: When should I use foreach instead of for?
Reach for foreach almost every time you walk through an array — it's cleaner, faster to read, and you can't get the bounds wrong. Use a plain for loop only when you genuinely need a counting number for its own sake (e.g. repeat something exactly 10 times, or step backwards), or when you need to skip by more than one. For associative arrays (named keys) foreach is the only sensible choice, because the keys aren't 0, 1, 2.
Q: What is the difference between while and do-while?
A while loop checks its condition BEFORE the first pass, so the body might run zero times. A do-while loop runs the body first and checks the condition AFTER, so it always runs at least once. Use do-while when the work must happen at least one time — for example, show a menu and then ask whether to show it again.
Q: What do break and continue do, and what does the number after them mean?
break stops the loop entirely and carries on with the code after it. continue skips the rest of the current pass and jumps straight to the next iteration. The optional number is the number of nested loops to act on: inside two loops, break 2 leaves both loops at once, and continue 2 skips to the next pass of the outer loop. Without a number they default to 1 (the innermost loop).
Q: Why did my array values change after a foreach loop with &$value?
When you write foreach ($arr as &$value) the & makes $value a reference — a live link to each element, so edits actually change the array. The trap is that after the loop, $value still points at the LAST element. If you reuse $value (or run another foreach over the same array) you can overwrite that last item. The fix is to call unset($value) immediately after the loop to break the link.
Q: What is an infinite loop and how do I avoid one?
An infinite loop is a loop whose condition never becomes false, so it runs forever and hangs your script. It almost always means you forgot to change the variable the condition depends on — for example a while ($i < 10) with no $i++ inside. Always make sure something in the loop body moves you toward the condition being false: increment a counter, shrink a list, or set a flag.
Mini-Challenge: FizzBuzz
No code is filled in this time — just a brief and an outline. FizzBuzz is the most famous loop exercise in programming, and it's a rite of passage. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments.
<?php
// 🎯 MINI-CHALLENGE: FizzBuzz (the classic loop exercise).
// No code is filled in — work from the steps, then run it.
//
// 1. Loop $i from 1 to 15 with a FOR loop.
// 2. For each $i, decide what to print:
// - divisible by 3 AND 5 -> print "FizzBuzz"
// - divisible by 3 only -> print "Fizz"
// - divisible by 5 only -> print "Buzz"
// - otherwise -> print the number $i
// (Tip: "divisible by 3" means $i % 3 === 0 . Check 3-AND-5 FIRST.)
// 3. Put each result on its own line (end with \n).
//
// ✅ Expected output:
// 1
// 2
// Fizz
// 4
// Buzz
// Fizz
// 7
// 8
// Fizz
// Buzz
// 11
// Fizz
// 13
// 14
// FizzBuzz
// your code here
?>🎉 Lesson Complete!
- ✅
forloops repeat a known number of times using start / condition / step - ✅
whilerepeats while a condition holds;do-whilealways runs at least once - ✅
foreach ($arr as $value)walks every item — the loop you'll use most - ✅
foreach ($arr as $key => $value)gives you the key and value together - ✅
break/continuesteer the loop, andbreak 2escapes nested loops - ✅ The
: … endforeach;/endfor;style keeps loops readable inside HTML templates - ✅ Next lesson: Functions — package loops and logic into reusable, named blocks you can call anywhere
Sign up for free to track which lessons you've completed and get learning reminders.