PHP Loop Control
Sometimes you need to exit a loop early or skip certain iterations. PHP provides
break and continue statements for precise control over loop execution,
including the ability to break out of multiple nested loops at once.
Break Statement
break immediately exits the loop, skipping all remaining iterations:
<?php
// Find first match and stop
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
foreach ($numbers as $num) {
if ($num === 5) {
echo "Found 5!";
break; // Exit loop immediately
}
echo "$num ";
}
// Output: 1 2 3 4 Found 5!
?>
| Statement | Effect |
|---|---|
break |
Exit the current loop immediately |
break 1 |
Same as break |
break 2 |
Exit two nested loops |
break n |
Exit n levels of nesting |
Click Run to execute your code
Continue Statement
continue skips the rest of the current iteration and moves to the next:
<?php
// Print only odd numbers
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 === 0) {
continue; // Skip even numbers
}
echo "$i ";
}
// Output: 1 3 5 7 9
// Skip specific values
$items = ["apple", "SKIP", "banana", "SKIP", "cherry"];
foreach ($items as $item) {
if ($item === "SKIP") {
continue;
}
echo "$item ";
}
// Output: apple banana cherry
?>
break= "I'm done with this loop entirely"continue= "Skip this one, try the next"
Break in Nested Loops
By default, break only exits the innermost loop. Use levels to break out of multiple loops:
<?php
// Without level - only exits inner loop
for ($i = 1; $i <= 3; $i++) {
for ($j = 1; $j <= 3; $j++) {
if ($j === 2) {
break; // Only exits inner loop
}
echo "($i,$j) ";
}
echo "| ";
}
// Output: (1,1) | (2,1) | (3,1) |
// With level 2 - exits both loops
for ($i = 1; $i <= 3; $i++) {
for ($j = 1; $j <= 3; $j++) {
if ($i === 2 && $j === 2) {
echo "Breaking out completely!";
break 2; // Exits BOTH loops
}
echo "($i,$j) ";
}
}
// Output: (1,1) (1,2) (1,3) (2,1) Breaking out completely!
?>
Break and Continue Levels
Both statements accept a level number for nested loop control:
Click Run to execute your code
Continue with Levels
<?php
// Skip entire row if condition met
$data = [
[1, 2, 3],
[4, -1, 6], // Contains negative
[7, 8, 9]
];
foreach ($data as $row) {
foreach ($row as $val) {
if ($val < 0) {
echo "(skip row) ";
continue 2; // Skip to next outer iteration
}
echo "$val ";
}
echo "| ";
}
// Output: 1 2 3 | (skip row) 7 8 9 |
?>
Break in Switch Within Loop
Remember: break in a switch only exits the switch, not the surrounding loop:
<?php
$commands = ["run", "stop", "run", "exit"];
foreach ($commands as $cmd) {
switch ($cmd) {
case "run":
echo "Running... ";
break; // Exits switch only, loop continues
case "stop":
echo "Stopped. ";
break; // Exits switch only
case "exit":
echo "Exiting!";
break 2; // Exits switch AND foreach loop
}
}
// Output: Running... Stopped. Running... Exiting!
?>
break 5) is a code smell.
If you need to break out of many nested loops, consider refactoring into a function and using
return instead.
Practical Patterns
Early Exit Pattern
<?php
function findUser($users, $id) {
foreach ($users as $user) {
if ($user['id'] === $id) {
return $user; // Found! Exit function
}
}
return null; // Not found
}
?>
Skip Invalid Items
<?php
$items = [10, null, 20, "", 30, false, 40];
$sum = 0;
foreach ($items as $item) {
if (!is_numeric($item)) {
continue; // Skip non-numeric values
}
$sum += $item;
}
echo "Sum: $sum"; // Sum: 100
?>
Limited Processing
<?php
$records = getLotsOfRecords();
$processed = 0;
$limit = 100;
foreach ($records as $record) {
processRecord($record);
$processed++;
if ($processed >= $limit) {
echo "Processed $limit records. Stopping.";
break;
}
}
?>
Common Mistakes
1. Using break instead of continue
<?php
$numbers = [1, 2, 3, 4, 5];
// โ WRONG: Stops at first even number
foreach ($numbers as $num) {
if ($num % 2 === 0) {
break; // Exits entire loop!
}
echo $num;
}
// Output: 1
// โ
CORRECT: Skips even numbers, continues loop
foreach ($numbers as $num) {
if ($num % 2 === 0) {
continue; // Skip to next iteration
}
echo $num;
}
// Output: 135
?>
2. Wrong level number
<?php
// โ WRONG: break 3 when only 2 loops exist
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
if ($condition) {
break 3; // Error: Cannot break 3 levels!
}
}
}
// โ
CORRECT: Use appropriate level
for ($i = 0; $i < 3; $i++) {
for ($j = 0; $j < 3; $j++) {
if ($condition) {
break 2; // Exit both loops
}
}
}
?>
3. Forgetting switch counts as a level
<?php
// โ WRONG: break 1 only exits switch
foreach ($items as $item) {
switch ($item) {
case "exit":
break; // Only exits switch!
}
echo "Still in loop\n"; // This runs!
}
// โ
CORRECT: break 2 exits switch AND loop
foreach ($items as $item) {
switch ($item) {
case "exit":
break 2; // Exits switch and foreach
}
}
?>
Exercise: Data Validator
Task: Process a batch of user registrations with validation.
Requirements:
- Skip users with empty email
- Skip users under 18 years old
- Stop processing if you find a banned email domain
- Count valid registrations
Show Solution
<?php
$registrations = [
["name" => "Alice", "email" => "[email protected]", "age" => 25],
["name" => "Bob", "email" => "", "age" => 30], // Empty email
["name" => "Carol", "email" => "[email protected]", "age" => 16], // Under 18
["name" => "David", "email" => "[email protected]", "age" => 28], // Banned domain!
["name" => "Eve", "email" => "[email protected]", "age" => 22]
];
$bannedDomains = ["spam.com", "fake.com", "temp.com"];
$validCount = 0;
foreach ($registrations as $user) {
// Skip empty email
if (empty($user['email'])) {
echo "Skipping {$user['name']}: No email\n";
continue;
}
// Skip underage
if ($user['age'] < 18) {
echo "Skipping {$user['name']}: Under 18\n";
continue;
}
// Check for banned domain
$emailDomain = substr($user['email'], strpos($user['email'], '@') + 1);
if (in_array($emailDomain, $bannedDomains)) {
echo "ALERT: Banned domain detected ({$emailDomain})!\n";
echo "Stopping all processing.\n";
break;
}
// Valid registration
echo "Registered: {$user['name']} ({$user['email']})\n";
$validCount++;
}
echo "\nTotal valid registrations: $validCount\n";
?>
Summary
- break: Exit the loop completely
- continue: Skip current iteration, continue to next
- break n: Exit n levels of nested loops
- continue n: Skip to next iteration of nth outer loop
- switch: Counts as a level for break/continue
- Best practice: Avoid high level numbers; refactor instead
- Alternative: Use
returnin functions for cleaner exits
What's Next?
Congratulations! You've mastered PHP control structures - conditions, switches, and all types of loops! Next, we'll learn about Functions - reusable blocks of code that make your programs modular and maintainable.
Enjoying these tutorials?