ZetCode

PHP foreach Loop

last modified October 22, 2026

The PHP foreach loop provides an easy way to iterate over arrays and objects. It automatically advances through each element, so there is no index to manage.

foreach syntax

The foreach loop has two forms. The first iterates over the values only. The second provides both keys and values.

foreach ($array as $value) { ... }
foreach ($array as $key => $value) { ... }

The loop variables are ordinary variables that remain available after the loop ends. The loop works on a copy of the array, so changing the array's contents inside a value-only loop does not affect the iteration.

Iterating over values

This example iterates over a simple indexed array and prints each value.

basic_foreach.php
<?php

declare(strict_types=1);

$colors = ['red', 'green', 'blue', 'yellow'];

foreach ($colors as $color) {
    echo "$color ";
}

On each iteration, the current element's value is assigned to $color. The loop runs once for every element in the array, in order. The trailing space in the string separates the words in the output.

$ php basic_foreach.php
red green blue yellow

Iterating over keys and values

The $key => $value form gives access to both the key and the value. This is the usual form for associative arrays.

foreach_keys.php
<?php

declare(strict_types=1);

$capitals = [
    'France' => 'Paris',
    'Germany' => 'Berlin',
    'Italy' => 'Rome'
];

foreach ($capitals as $country => $capital) {
    echo "The capital of $country is $capital\n";
}

The keys are the country names and the values are the capitals. Both are assigned on every iteration, and the output follows the insertion order of the array.

$ php foreach_keys.php
The capital of France is Paris
The capital of Germany is Berlin
The capital of Italy is Rome

Modifying array elements by reference

By default, the loop variable is a copy of the element, so assigning to it does not change the array. Putting & before the loop variable makes it a reference to the element, so changes are written back to the array.

foreach_modify.php
<?php

declare(strict_types=1);

$numbers = [1, 2, 3, 4, 5];

foreach ($numbers as &$number) {
    $number *= 2;
}
unset($number);

print_r($numbers);

Each value is doubled through the reference. The unset($number) call after the loop is important; it breaks the reference to the last element. Without it, the variable still points at the last element and can cause the pitfall described in the next section.

$ php foreach_modify.php
Array
(
    [0] => 2
    [1] => 4
    [2] => 6
    [3] => 8
    [4] => 10
)

Reference pitfall

If the reference is not unset and the same variable name is reused in a second loop, the last element of the array is overwritten on every iteration of that second loop. This example shows the effect.

foreach_pitfall.php
<?php

$a = [1, 2, 3];

foreach ($a as &$v) {}
foreach ($a as $v) {}

print_r($a);

The first loop leaves $v referencing the last element. The second loop assigns each value to $v, which writes into that last element. The result is [1, 2, 2], not [1, 2, 3].

$ php foreach_pitfall.php
Array
(
    [0] => 1
    [1] => 2
    [2] => 2
)

Nested loops with multidimensional arrays

An array can contain other arrays. Nested foreach loops process each row and then each cell in that row.

foreach_multidimensional.php
<?php

declare(strict_types=1);

$matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

foreach ($matrix as $row) {
    foreach ($row as $cell) {
        echo "$cell ";
    }
    echo "\n";
}

The outer loop visits each row. The inner loop visits each cell of the current row. The echo "\n" after the inner loop starts a new line for each row.

$ php foreach_multidimensional.php
1 2 3
4 5 6
7 8 9

Destructuring with list

When each element is itself an array, list() (or the short [...] syntax) unpacks its items into separate variables inside the foreach header.

foreach_list.php
<?php

declare(strict_types=1);

$people = [
    ['John', 'Doe', 30],
    ['Jane', 'Smith', 25],
    ['Bob', 'Johnson', 45]
];

foreach ($people as list($firstName, $lastName, $age)) {
    echo "$firstName $lastName is $age years old\n";
}

Each sub-array is split into $firstName, $lastName, and $age. The number of variables must match the structure of the sub-arrays.

$ php foreach_list.php
John Doe is 30 years old
Jane Smith is 25 years old
Bob Johnson is 45 years old

Breaking and continuing

The continue statement skips the rest of the current iteration. The break statement ends the loop.

foreach_control.php
<?php

declare(strict_types=1);

$values = [10, 20, 30, 40, 50, 60];

foreach ($values as $value) {
    if ($value == 30) {
        continue;
    }
    if ($value == 50) {
        break;
    }
    echo "$value ";
}

The value 30 is skipped by continue. The loop stops at 50 because of break, so 60 is never reached. Only 10, 20, and 40 are printed.

$ php foreach_control.php
10 20 40

Iterating over object properties

When foreach is applied to an object, it iterates over the object's accessible properties. Outside the class, only public properties are visible.

foreach_object.php
<?php

declare(strict_types=1);

class Book {
    public $title = 'PHP Guide';
    public $author = 'John Doe';
    public $price = 29.99;
}

$book = new Book();

foreach ($book as $property => $value) {
    echo "$property: $value\n";
}

The property names become the keys and their values become the values. To customize iteration over an object, implement the Iterator or IteratorAggregate interface.

$ php foreach_object.php
title: PHP Guide
author: John Doe
price: 29.99

Alternative syntax

PHP also supports a colon-based syntax, which is common in templates that mix PHP and HTML. The loop ends with endforeach.

foreach_alt.php
<?php

$fruits = ['apple', 'banana'];

foreach ($fruits as $fruit):
    echo "$fruit\n";
endforeach;

The colon replaces the opening brace, and endforeach replaces the closing brace. The behavior is identical to the braced form.

$ php foreach_alt.php
apple
banana

Empty arrays

If the array is empty, the loop body never runs. No error is raised.

foreach_empty.php
<?php

$empty = [];

foreach ($empty as $item) {
    echo "never printed\n";
}
echo "done\n";

The body is skipped and execution continues after the loop. This is why foreach is safe to use on arrays that may have no elements.

$ php foreach_empty.php
done

Non-array values

foreach works only on arrays and objects. Passing any other type produces a warning, and the loop body is not executed. The script itself keeps running. The warning text is shown on the output of the PHP CLI; its exact wording and location depend on your configuration.

foreach_nonarray.php
<?php

$value = 42;

foreach ($value as $item) {
    echo $item;
}
echo "after\n";

Because $value is an integer, the loop cannot iterate over it. The script still reaches the final echo. Check with is_iterable before looping over values of unknown type.

$ php foreach_nonarray.php
after

Best practices

Source

PHP foreach documentation

In this article we have covered the foreach loop with examples of value and key iteration, reference modification, nested arrays, destructuring, object iteration, and common pitfalls.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all PHP tutorials.