Continue Statement
What Is continue ? In simple terms: continue skips the rest of the current loop iteration and moves on to the next one. The loop itself keeps running. Technically: continue ends the current iteration
What Is continue?
In simple terms: continue skips the rest of the current loop iteration and moves on to the next one. The loop itself keeps running.
Technically: continue ends the current iteration of a for, foreach, while, or do...while loop. Control jumps to the point where the loop decides whether to run again: the update and condition in a for loop, the condition in while/do...while, or the next element in foreach. An optional numeric argument (continue 2) applies this to an enclosing loop.
continue vs break
| Statement | What Happens |
|---|---|
continue | Skip this item, keep looping |
break | Stop the whole loop |
Why It Is Needed
When processing a list, some items should simply be skipped — invalid records, inactive users, empty lines, items already handled. continue handles these cases at the top of the loop body, so the main processing code does not need to be wrapped in an if block.
Syntax
continue; // next iteration of the innermost loop
continue 2; // next iteration of the loop one level up
Example: Skipping Odd Numbers
<?php
for ($i = 1; $i <= 10; $i++) {
if ($i % 2 !== 0) {
continue;
}
echo $i . ' ';
}
echo "\n";
Output
2 4 6 8 10
How It Works
- For odd numbers,
$i % 2 !== 0is true andcontinueruns. - The
echobelow is skipped for that iteration. - In a
forloop, the update$i++still runs aftercontinue, then the condition is checked again. - Even numbers reach the
echo.
continue as a Guard Clause in Loops
Without continue, filtering often leads to nested blocks:
foreach ($users as $user) {
if ($user['active']) {
if ($user['email'] !== '') {
// ... main processing, deeply indented ...
}
}
}
With continue, each skip condition is handled up front, and the main work stays at the top indentation level:
<?php
$users = [
['name' => 'Asha', 'email' => 'asha@example.com', 'active' => true],
['name' => 'Bala', 'email' => '', 'active' => true],
['name' => 'Charu', 'email' => 'charu@example.com', 'active' => false],
['name' => 'Dev', 'email' => 'dev@example', 'active' => true],
['name' => 'Esha', 'email' => 'esha@example.com', 'active' => true],
];
$sent = 0;
foreach ($users as $user) {
if (!$user['active']) {
echo "Skipping {$user['name']}: inactive\n";
continue;
}
if (filter_var($user['email'], FILTER_VALIDATE_EMAIL) === false) {
echo "Skipping {$user['name']}: invalid email\n";
continue;
}
echo "Sending newsletter to {$user['email']}\n";
$sent++;
}
echo "Sent: $sent\n";
Output
Sending newsletter to asha@example.com
Skipping Bala: invalid email
Skipping Charu: inactive
Skipping Dev: invalid email
Sending newsletter to esha@example.com
Sent: 2
Why This Structure Works Well
- Each reason for skipping is written once, with a clear message.
- The main action (sending) is not nested inside any
if. - Adding a new skip rule means adding one more guard at the top.
This is the loop equivalent of guard clauses with return in functions (see PHP Nested if).
continue in while Loops: The Infinite Loop Trap
In a for loop, the update expression runs automatically after continue. In a while loop, there is no separate update step — if the counter is updated at the end of the body, continue skips that update:
// WARNING: infinite loop
$i = 0;
while ($i < 5) {
if ($i === 2) {
continue; // $i++ below is skipped, so $i stays 2 forever
}
echo $i;
$i++;
}
When $i reaches 2, continue jumps back to the condition without increasing $i, so the loop repeats with $i === 2 forever.
Fix: Update Before continue
<?php
$i = 0;
while ($i < 5) {
$i++;
if ($i === 3) {
continue;
}
echo $i . ' ';
}
echo "\n";
Output
1 2 4 5
Moving $i++ to the start of the body guarantees it runs in every iteration. (Because the increment now happens first, the loop prints 1 to 5 instead of 0 to 4.) Alternatively, use a for loop, where the update is always executed.
continue 2 in Nested Loops
A plain continue affects the innermost loop. continue 2 skips the rest of the current iteration of the outer loop — including any remaining inner iterations.
Example: Skip an Entire Order When One Item Is Invalid
<?php
$orders = [
['id' => 1, 'items' => [['sku' => 'A', 'qty' => 2], ['sku' => 'B', 'qty' => 1]]],
['id' => 2, 'items' => [['sku' => 'C', 'qty' => 0], ['sku' => 'D', 'qty' => 3]]],
['id' => 3, 'items' => [['sku' => 'E', 'qty' => 1]]],
];
foreach ($orders as $order) {
foreach ($order['items'] as $item) {
if ($item['qty'] <= 0) {
echo "Order {$order['id']} skipped: invalid quantity for {$item['sku']}\n";
continue 2;
}
}
echo "Order {$order['id']} is valid\n";
}
Output
Order 1 is valid
Order 2 skipped: invalid quantity for C
Order 3 is valid
How It Works
- For order 2, the first item
Chas quantity0. continue 2immediately moves to the next order: itemDis not checked, and the line "Order 2 is valid" after the inner loop is skipped.- A plain
continuewould only skip to the next item, and order 2 would then be reported as valid.
The rules for the argument are the same as for break: it must be a positive integer literal, and a switch counts as one level.
continue Inside switch
Inside a switch within a loop, a plain continue targets the switch, which behaves like break. PHP warns about this at compile time ("continue" targeting switch is equivalent to "break"). Use continue 2 to move to the loop's next iteration:
<?php
foreach (['INFO ok', 'DEBUG verbose', 'ERROR failed'] as $line) {
switch (strtok($line, ' ')) {
case 'DEBUG':
continue 2; // skip debug lines entirely
case 'ERROR':
echo "!! ";
break;
}
echo $line . "\n";
}
Output
INFO ok
!! ERROR failed
The DEBUG line is skipped completely; ERROR lines get a marker before the line is printed.
continue vs array_filter()
When the goal is only to select items, array_filter() can replace a loop with continue:
<?php
$scores = [78, 0, 92, 45, 0, 88];
$valid = [];
foreach ($scores as $score) {
if ($score === 0) {
continue;
}
$valid[] = $score;
}
$alsoValid = array_values(array_filter($scores, fn($score) => $score !== 0));
echo implode(', ', $valid) . "\n";
echo implode(', ', $alsoValid) . "\n";
Output
78, 92, 45, 88
78, 92, 45, 88
array_filter()keeps elements for which the callback returnstrue.- It preserves the original keys, so
array_values()re-indexes the result from0.
Use array_filter() for pure selection, and a loop with continue when each item needs further processing, logging, or several skip rules with different messages.
Common Mistakes
Skipping the Counter Update in while Loops
Effect: Infinite loop.
Fix: Update the counter before any continue, or use for.
Using continue When break Was Intended
Effect: The loop keeps running after the item you were looking for was found.
Fix: Use break to stop the loop; continue only skips one item.
Plain continue Inside switch
Effect: Acts like break; the rest of the loop body still runs.
Fix: Use continue 2.
Too Many Skip Conditions Scattered Through the Body
Effect: Hard to see which items are processed.
Fix: Place all continue guards at the top of the loop body, before the main work.
continue Outside a Loop
Effect: Fatal error: 'continue' not in the 'loop' or 'switch' context.
Fix: Only use continue inside loops.
Best Practices
- Use
continueat the top of the loop body to skip items that should not be processed. - Give each skip a clear reason (a log message or comment).
- In
whileloops, update loop variables before anycontinue. - Use
continue 2to skip an outer item from inside a nested loop or aswitch. - Prefer
array_filter()for simple selection without further processing.
Official reference: https://www.php.net/manual/en/control-structures.continue.php