Iterating Arrays
Reading through an array's elements one at a time is one of the most common operations in any PHP script. foreach is the tool you will reach for the vast majority of the time, but PHP arrays also carry an internal pointer with its own set of functions, and there is an entire Iterator interface for objects that behave like arrays. This page ties those pieces together.
foreach, recap
foreach walks every element of an array in insertion order, without you having to manage an index or a pointer yourself. You can pull just the value, or the key and the value together.
Values only, and key + value
<?php
$scores = ["Ana" => 91, "Bo" => 78, "Cy" => 85];
foreach ($scores as $score) {
echo $score . " ";
}
echo "\n";
foreach ($scores as $name => $score) {
echo "{$name}: {$score}\n";
}91 78 85 Ana: 91 Bo: 78 Cy: 85
By default foreach works on a copy of the array, so modifying $score inside the loop does not change $scores. To modify the original array while iterating, take the value by reference with & - but remember to unset() that reference variable right after the loop, or it will keep pointing at the last element and silently corrupt the next loop that reuses the same variable name.
Modifying in place with a reference
<?php
$scores = ["Ana" => 91, "Bo" => 78, "Cy" => 85];
foreach ($scores as $name => &$score) {
$score += 5; // curve everyone's score
}
unset($score); // break the reference - important!
print_r($scores);Array
(
[Ana] => 96
[Bo] => 83
[Cy] => 90
)array_walk() for side effects
array_walk() applies a callback to every element of an array, passing the value (by reference, so it can modify it) and the key. It is most useful when you already have a named function or need to pass extra context via a third argument, rather than writing an inline foreach.
Applying a callback to every element
<?php
$prices = ["apple" => 0.50, "banana" => 0.25];
array_walk($prices, function (&$price, $name) {
$price = round($price * 1.08, 2); // apply 8% tax, modify by reference
});
print_r($prices);Array
(
[apple] => 0.54
[banana] => 0.27
)The internal pointer: current(), next(), reset()
Every PHP array carries an internal pointer that tracks "the current element," independent of foreach. current() reads the value the pointer is on, next() advances it, reset() moves it back to the first element, and end() jumps to the last. These functions predate foreach and are rarely needed in modern code, but you will still encounter them in older codebases, and they matter if you need to manually walk two arrays in lockstep.
Manual pointer walking
<?php $colors = ["red", "green", "blue"]; echo current($colors); // red - pointer starts at the first element echo "\n"; echo next($colors); // green - advances and returns the new current value echo "\n"; echo next($colors); // blue echo "\n"; var_dump(next($colors)); // bool(false) - moved past the end
red green blue bool(false)
Beyond arrays: the Iterator interface
foreach is not limited to arrays - it also works on any object that implements PHP's Iterator interface (with methods like current(), key(), next(), rewind(), and valid()), or the simpler IteratorAggregate interface. This is how custom collection classes, database result sets, and generators (functions using yield) all plug into the same foreach syntax you already know. That is a deeper topic on its own, but recognizing the name is useful the first time you see implements Iterator in a class definition.
foreachis almost always the right default - reach for the internal-pointer functions only when you specifically need manual, non-linear control.Always
unset()a by-reference loop variable immediately after the loop ends.array_walk()mutates in place and returnstrueon success, unlikearray_map()which returns a brand-new array.Generators (
yield) let you write iterable logic without building the whole array in memory first - worth knowing exists even before you need it.