break and continue both alter a loop's normal flow, but in genuinely different ways — break exits the loop entirely, while continue only skips the rest of the current iteration and moves to the next one.
break: exiting a loop entirely
foreach ($users as $user) {
if ($user->id === $targetId) {
$foundUser = $user;
break;
}
}
Once the target user is found, there's no reason to keep checking the remaining users — break stops the loop immediately at that point, avoiding unnecessary further iterations once the needed result has already been found.
continue: skipping to the next iteration
foreach ($products as $product) {
if (!$product->isActive) {
continue;
}
echo $product->name . PHP_EOL;
}
continue skips just the rest of the current iteration's code (the echo here) for inactive products, but the loop itself keeps running through every remaining product — a genuinely different effect from break, which would have stopped checking any further products entirely.
Both work identically across for, foreach, while, and do-while loops
for ($i = 0; $i < 10; $i++) {
if ($i === 5) break;
echo $i;
}
// Outputs: 01234
for ($i = 0; $i < 10; $i++) {
if ($i % 2 === 0) continue;
echo $i;
}
// Outputs: 13579 — even numbers skipped, loop still runs to completion
Breaking or continuing out of a specific nested loop level
foreach ($categories as $category) {
foreach ($category->products as $product) {
if ($product->isOutOfStock) {
continue 2; // skip to the next category, not just the next product
}
echo $product->name;
}
}
Both break and continue accept an optional numeric argument specifying how many nested loop levels to affect — continue 2 here skips straight to the next iteration of the outer (category) loop, rather than just the inner (product) loop, which a plain unqualified continue would do instead.
A common mistake: using break where continue was intended
// WRONG — this stops processing all remaining products entirely
foreach ($products as $product) {
if (!$product->isActive) {
break; // should be continue
}
processProduct($product);
}
Mixing these up is a subtle logic bug, not a syntax error — both statements are valid anywhere inside a loop, so PHP won't flag the mistake; the bug only surfaces as unexpectedly incomplete processing, since break here would silently stop the loop at the very first inactive product rather than skipping past it.
Using break to exit a switch statement
switch ($status) {
case 'pending':
echo 'Order is pending';
break;
case 'shipped':
echo 'Order has shipped';
break;
default:
echo 'Unknown status';
}
Inside a switch, break serves a related but distinct purpose — preventing "fall-through" into the next case block — worth knowing as a related, commonly confused use of the same keyword, distinct from its loop-exiting behavior covered above.