for Loop
Use for when you need precise numeric control:
<?php
// Standard counter
for ($i = 0; $i < 5; $i++) {
echo $i . " "; // 0 1 2 3 4
}
// Count backwards
for ($i = 10; $i >= 1; $i--) {
echo $i . " "; // 10 9 8 7 ... 1
}
// Step by 2
for ($i = 0; $i <= 20; $i += 2) {
echo $i . " "; // 0 2 4 ... 20
}
// Multiple counters
for ($i = 0, $j = 100; $i < 5; $i++, $j -= 10) {
echo "$i:$j ";
}
foreach Loop
The default choice for arrays and iterables:
<?php
$colors = ["red", "green", "blue"];
// Value only
foreach ($colors as $color) {
echo $color . "\n";
}
// Key + value
foreach ($colors as $index => $color) {
echo "$index: $color\n";
}
// Associative
$user = ["name" => "Ruban", "age" => 30];
foreach ($user as $field => $value) {
echo "$field = $value\n";
}
// By reference - modify in place
foreach ($colors as &$color) {
$color = strtoupper($color);
}
unset($color); // critical!
// Destructure values inline (PHP 7.1+)
$users = [["alice", 30], ["bob", 25]];
foreach ($users as [$name, $age]) {
echo "$name is $age\n";
}
If you write foreach ($arr as &$item), ALWAYS follow with unset($item);. The reference outlives the loop and any future assignment to $item silently mutates the last array element. This bug has bitten every PHP developer at least once.
while Loop
Repeat as long as a condition is true. Checks before each iteration:
<?php
$i = 0;
while ($i < 5) {
echo $i . " ";
$i++;
}
// Reading lines from a file
$fh = fopen("data.txt", "r");
while (($line = fgets($fh)) !== false) {
echo $line;
}
fclose($fh);
// Reading database rows
while ($row = $stmt->fetch()) {
process($row);
}
do-while Loop
Runs the body at least once, then checks the condition:
<?php
// Prompt until user enters valid input
do {
$answer = readline("Continue? (y/n): ");
} while ($answer !== "y" && $answer !== "n");
// Retry with exponential backoff
$attempt = 0;
$result = null;
do {
$result = tryRequest();
if ($result !== null) break;
sleep(2 ** $attempt);
$attempt++;
} while ($attempt < 5);
break & continue
<?php
// break - exit the loop entirely
foreach ($users as $user) {
if ($user->isBanned()) {
echo "Banned user found, stopping";
break;
}
sendEmail($user);
}
// continue - skip to next iteration
foreach ($numbers as $n) {
if ($n < 0) continue; // skip negatives
echo sqrt($n) . "\n";
}
// break N - exit nested loops
foreach ($categories as $cat) {
foreach ($cat->items as $item) {
if ($item->id === $needle) {
$found = $item;
break 2; // exit BOTH loops
}
}
}
Nested Loops
<?php
// Print a multiplication table
for ($row = 1; $row <= 5; $row++) {
for ($col = 1; $col <= 5; $col++) {
printf("%4d", $row * $col);
}
echo "\n";
}
// Walk a 2D grid
foreach ($grid as $y => $row) {
foreach ($row as $x => $cell) {
if ($cell === "*") echo "Found at ($x, $y)\n";
}
}
Nested loops over the same dataset are quadratic. With 1,000 items that's 1,000,000 operations. Use a hash map (array_flip()) or pre-indexed lookups instead when possible.
Loop Performance Tips
- Hoist
count()out of the loop condition:for ($i = 0, $n = count($arr); $i < $n; $i++) - Prefer
foreachoverforwith array access - it's faster. - Use generators for huge datasets instead of building giant arrays.
- Avoid
foreachby-reference unless you genuinely need to mutate. - array_map/array_filter are not magically faster -
foreachis fine. - Break early when you've found what you need.