Skip to main content

    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

    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".

    A basic counting loop
    <?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
    ?>
    Output
    Count: 1
    Count: 2
    Count: 3
    Count: 4
    Count: 5
    Done!
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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.

    Loop until a total is reached
    <?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";
    ?>
    Output
    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.
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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").

    The body runs once even when the condition is false
    <?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";
    ?>
    Output
    Body ran with count = 10
    Notice the body ran once despite the false condition.
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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.

    foreach ($arr as $value)
    <?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
    ?>
    Output
    I like Apple
    I like Banana
    I like Cherry
    I like Date
    That's 4 fruits.
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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.

    foreach ($arr as $key => $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";
    }
    ?>
    Output
    coffee costs $3.5
    muffin costs $2
    juice costs $4.25
    [0] red
    [1] green
    [2] blue
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    Notice 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.

    break, continue, and break 2
    <?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";
        }
    }
    ?>
    Output
    === 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.
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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.

    🎯 Your turn: count down with a for loop
    <?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!
    ?>
    Output
    5
    4
    3
    2
    1
    Lift off!
    Fill the first ___ 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.

    🎯 Your turn: foreach with key => value
    <?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
    ?>
    Output
    Maya scored 88
    Owen scored 73
    Priya scored 95
    Set the first blank to $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.

    The colon / end-word style in a template
    <?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; ?>
    Output
    <ul>
        <li>Ada</li>
        <li>Linus</li>
        <li>Grace</li>
    </ul>
    
    <p>Row 1</p>
    <p>Row 2</p>
    <p>Row 3</p>
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    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.

    Sum a cart, skipping out-of-stock items
    <?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);
    ?>
    Output
    Laptop    $999.00
    Mouse     $25.50
    Keyboard: out of stock (skipped)
    Monitor   $180.75
    -------------------
    Items: 3   Total: $1205.25
    This is real code — run it for free atonecompiler.com/phpor in your own editor.

    Common 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 $value a live link to each element, and it still points at the last item after the loop. Reusing $value then overwrites that item. Fix: call unset($value); right after the loop.
    • Weird results from adding/removing items during a foreachforeach works 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 <= 5 would 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 with endforeach;. Don't mix the two styles: either { … } or : … endforeach;

    Pro Tips

    • 💡 Default to foreach for arrays. It can't go out of bounds and reads cleaner than a for with an index. Save plain for for when you truly need a counting number.
    • 💡 Break early once you've found it. Searching a list? break the 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

    SyntaxExampleWhat 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 2break 2;Exit one (or N nested) loops
    continue / continue 2continue;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.

    🎯 Mini-Challenge: write FizzBuzz from 1 to 15
    <?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
    ?>
    Loop 1 to 15, print Fizz / Buzz / FizzBuzz on the multiples and the number otherwise. Remember to test the 3-AND-5 case first.

    🎉 Lesson Complete!

    • for loops repeat a known number of times using start / condition / step
    • while repeats while a condition holds; do-while always 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 / continue steer the loop, and break 2 escapes 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.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service