foreach and the while/list/each methods are not completely identical, and there are occasions where one way is beneficial over the other.
<?php
$arr = array(1,2,3,4,5,6,7,8,9);
foreach($arr as $key=>$value)
{
unset($arr[$key + 1]);
echo $value . PHP_EOL;
}
?>
Output:
1 2 3 4 5 6 7 8 9
<?php
$arr = array(1,2,3,4,5,6,7,8,9);
while (list($key, $value) = each($arr))
{
unset($arr[$key + 1]);
echo $value . PHP_EOL;
}
?>
Output:
1 3 5 7 9
[EDIT BY danbrown AT php DOT net: Contains a typofix by (scissor AT phplabs DOT pl) on 30-JAN-2009.]
foreach
(PHP 4, PHP 5)
The foreach construct provides an easy way to iterate over arrays. foreach works only on arrays and objects, and will issue an error when you try to use it on a variable with a different data type or an uninitialized variable. There are two syntaxes:
foreach (array_expression as $value) statement foreach (array_expression as $key => $value) statement
The first form loops over the array given by array_expression. On each iteration, the value of the current element is assigned to $value and the internal array pointer is advanced by one (so on the next iteration, you'll be looking at the next element).
The second form will additionally assign the current element's key to the $key variable on each iteration.
It is possible to customize object iteration.
Note:
When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.
As foreach relies on the internal array pointer, changing it within the loop may lead to unexpected behavior.
In order to be able to directly modify array elements within the loop precede $value with &. In that case the value will be assigned by reference.
<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
unset($value); // break the reference with the last element
?>
Referencing $value is only possible if the iterated array can be referenced (i.e. if it is a variable). The following code won't work:
<?php
foreach (array(1, 2, 3, 4) as &$value) {
$value = $value * 2;
}
?>
Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().
Note:
foreach does not support the ability to suppress error messages using '@'.
You may have noticed that the following are functionally identical:
<?php
$arr = array("one", "two", "three");
reset($arr);
while (list(, $value) = each($arr)) {
echo "Value: $value<br />\n";
}
foreach ($arr as $value) {
echo "Value: $value<br />\n";
}
?>
The following are also functionally identical:
<?php
$arr = array("one", "two", "three");
reset($arr);
while (list($key, $value) = each($arr)) {
echo "Key: $key; Value: $value<br />\n";
}
foreach ($arr as $key => $value) {
echo "Key: $key; Value: $value<br />\n";
}
?>
Some more examples to demonstrate usage:
<?php
/* foreach example 1: value only */
$a = array(1, 2, 3, 17);
foreach ($a as $v) {
echo "Current value of \$a: $v.\n";
}
/* foreach example 2: value (with its manual access notation printed for illustration) */
$a = array(1, 2, 3, 17);
$i = 0; /* for illustrative purposes only */
foreach ($a as $v) {
echo "\$a[$i] => $v.\n";
$i++;
}
/* foreach example 3: key and value */
$a = array(
"one" => 1,
"two" => 2,
"three" => 3,
"seventeen" => 17
);
foreach ($a as $k => $v) {
echo "\$a[$k] => $v.\n";
}
/* foreach example 4: multi-dimensional arrays */
$a = array();
$a[0][0] = "a";
$a[0][1] = "b";
$a[1][0] = "y";
$a[1][1] = "z";
foreach ($a as $v1) {
foreach ($v1 as $v2) {
echo "$v2\n";
}
}
/* foreach example 5: dynamic arrays */
foreach (array(1, 2, 3, 4, 5) as $v) {
echo "$v\n";
}
?>
Unpacking nested arrays with list()
(PHP 5 >= 5.5.0)
PHP 5.5 added the ability to iterate over an array of arrays and unpack the nested array into loop variables by providing a list() as the value.
For example:
<?php
$array = [
[1, 2],
[3, 4],
];
foreach ($array as list($a, $b)) {
// $a contains the first element of the nested array,
// and $b contains the second element.
echo "A: $a; B: $b\n";
}
?>
The above example will output:
A: 1; B: 2 A: 3; B: 4
You can provide fewer elements in the list() than there are in the nested array, in which case the leftover array values will be ignored:
<?php
$array = [
[1, 2],
[3, 4],
];
foreach ($array as list($a)) {
// Note that there is no $b here.
echo "$a\n";
}
?>
The above example will output:
1 3
A notice will be generated if there aren't enough array elements to fill the list():
<?php
$array = [
[1, 2],
[3, 4],
];
foreach ($array as list($a, $b, $c)) {
echo "A: $a; B: $b; C: $c\n";
}
?>
The above example will output:
Notice: Undefined offset: 2 in example.php on line 7 A: 1; B: 2; C: Notice: Undefined offset: 2 in example.php on line 7 A: 3; B: 4; C:

You can also use the alternative syntax for the foreach cycle:
<?php
foreach($array as $element):
#do something
endforeach;
?>
Just thought it worth mentioning.
I want to add some inline comments to dtowell's piece of code about the iteration by reference:
<?php
$a = array('abe','ben','cam');
foreach ($a as $k=>&$n)
$n = strtoupper($n);
# At the end of this cycle the variable $n refers to the same memory as $a[2]
# So when the second "foreach" assigns a value to $n :
foreach ($a as $k=>$n) // notice NO reference here!
echo "$n\n";
# it is also modifying $a[2] .
# So on the three repetitions of the second "foreach" the array will look like:
# 1. ('abe','ben','abe') - assigned the value of the first element to the last element
# 2. ('abe','ben','ben') - assigned the value of the second element to the last element
# 3. ('abe','ben','ben') - assigned the value of the third element to itself
print_r($a);
?>
References created by foreach hang around past their best-used-by date. For example, the following:
<?php
$a = array('abe','ben','cam');
foreach ($a as $k=>&$n)
$n = strtoupper($n);
foreach ($a as $k=>$n) // notice NO reference here!
echo "$n\n";
print_r($a);
?>
will result in:
ABE
BEN
BEN
Array
(
[0] => ABE
[1] => BEN
[2] => BEN
)
This function find well the words, add well adds a () around short words, but the
array at the end of th function is the same as at the beginning.
<?php
function isole_mots($chaine)
{
$chaine = "le petit chat est fou";
$mots = preg_split('/[!,-.;?:()[ ]/', $chaine, -1, PREG_SPLIT_NO_EMPTY);
foreach ($mots as $mot)
{
if (strlen($mot) <= 3)
$mot = "(".$mot.")";
print " inside foreach $mot <br>";
}
print "after foreach array mots";
print_r($mots);
die();
return $mots;
}
?>
inside foreach (le)
inside foreach petit
inside foreach chat
inside foreach (est)
inside foreach (fou)
after foreach array motsArray ( [0] => le [1] => petit [2] => chat [3] => est [4] => fou )
<?php
$d3 = array('a'=>array('b'=>'c'));
foreach($d3['a'] as &$v4){}
foreach($d3 as $v4){}
var_dump($d3);
?>
will get something look like this:
array(1) {
["a"]=>
array(1) {
["b"]=>
&array(1) {
["b"]=>
*RECURSION*
}
}
}
then you try to walk some data with this array.
the script run out of memory and connect reset by peer
the document says:
Warning
Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset().
so what I learn is that NEVER ignore """Warning""" in document....
For those who'd like to traverse an array including just added elements (within this very foreach), here's a workaround:
<?php
$values = array(1 => 'a', 2 => 'b', 3 => 'c');
while (list($key, $value) = each($values)) {
echo "$key => $value \r\n";
if ($key == 3) {
$values[4] = 'd';
}
if ($key == 4) {
$values[5] = 'e';
}
}
?>
the code above will output:
1 => a
2 => b
3 => c
4 => d
5 => e
"Reference of a $value and the last array element remain even after the foreach loop. It is recommended to destroy it by unset()."
I cannot stress this point of the documentation enough! Here is a simple example of exactly why this must be done:
<?php
$arr1 = array("a" => 1, "b" => 2, "c" => 3);
$arr2 = array("x" => 4, "y" => 5, "z" => 6);
foreach ($arr1 as $key => &$val) {}
foreach ($arr2 as $key => $val) {}
var_dump($arr1);
var_dump($arr2);
?>
The output is:
array(3) { ["a"]=> int(1) ["b"]=> int(2) ["c"]=> &int(6) }
array(3) { ["x"]=> int(4) ["y"]=> int(5) ["z"]=> int(6) }
Notice how the last index in $arr1 is now the value from the last index in $arr2!
If you wondered how to create a list of all possible combinations of variable amount of arrays (multiple foreach), you might use this:
<?php
$a[0] = array('a1','a2');
$a[1] = array('b1','b2','b3');
$a[2] = array('c1','c2');
function getAllCombinations($a,$i,$s)
{
foreach ($a[$i] as $v)
{
if (!isset($a[$i+1]))
{
echo $s.$v."\n";
} else {
getAllCombinations($a,$i+1,$s.$v);
}
}
return $s;
}
echo getAllCombinations($a,0,'');
?>
the result:
a1b1c1
a1b1c2
a1b2c1
a1b2c2
a1b3c1
a1b3c2
a2b1c1
a2b1c2
a2b2c1
a2b2c2
a2b3c1
a2b3c2
You can even iterate through "dynamic" arrays that do not physically exist, but are objects that implement Iterator interface. They don't need to be stored in memory when foreach starts.
Consider the array that contains some values (I called it $allValues in the example below) and we want to have only some of them (eg. the ones that are dividable by 2). I create an object that would serve as dynamic array, that means it would "dynamically update" its values together with $allValues. The main advantage is that I store only one array, and it's the only array I serialize.
An object of MyIter class will not contain any values itself:
<?php
class MyIter implements Iterator { // you can implement ArrayAccess and Countable interfaces too, this will make class MyIter behave like a "real" array
private $position = 0; // an internal position of the current element
// please note that $position has nothing common with $allValues!
private function getTable(){ // prepare a temporary "static" table of all objects in the class
global $allValues;
$result=array(); // temporary variable
foreach($allValues as $obj){
if($obj % 2 == 0) // check if the value is even
$result[]=$obj; // if yes, I want it
}
return $result;
}
// the all below declared methods are public and belong to the Iterator interface
function rewind() { // a method to start iterating
$this->position = 0; // just move to the beginning
}
function current() { // retrieves the current element
$table=$this->getTable(); // let us prepare a table
return $table[$this->position]; // and return the current element
}
function key() { // retrieves the current element's key
return $this->position; // this is used by foreach(... as $key=>$value), not important here
}
function next() { // move to next element
++$this->position;
}
function valid() { // check if the current element is valid (ie. if it exists)
return array_key_exists($this->position, $this->getTable());
}
} // end of class
// now prepare the array of 12 elements
$allValues=array(0,1,2,3,4,5,6,7,8,9,10,11);
//we would like to have a dynamic array of all even values
$iterator=new MyIter();
foreach($iterator as $value){
echo $value."<br />";
}
?>
This will result in:
0
2
4
6
8
10
(You may also like to see what var_dump($iterator) produces).
Another great advantage is that you can modify the main table "on-the-fly" and it has its impact. Let us modify the last foreach loop:
<?php
// ...all above shall stay as it was
foreach($iterator as $value){
echo $value."<br />";
if($value==6){
$allValues=array(2,3);
echo "I modified source array!<br />";
}
}
?>
This produces now:
0
2
4
6
I modified source array!
However, if you feel it is rather a catastrophic disadvantage (maybe for example, it shows the values 0, 4, and 6 which were removed when we reached 6), and wish to have a "static" array that will iterate even in modified objects, just call getTable() in rewind() method and save it in temporary (private perhaps) field. In my example getTable() is called every iteration, and it calls another foreach through $allValues, which together might be time-consuming. Consider what you need.
Alright, I had a little error. I had one foreach() declaration, and then another foreach() declaration.
They went:
<?php
//$connections is an array of Socket resources
foreach ($connections as $key => &$value) {
//the code here is impertinent
}
//$users is an associative array
foreach ($users as $key => &$value) {
//the code here is impertinent
}
?>
Alright, now, what error was produced as a result of this?
This one:
"Warning: Cannot use scalar value as array in filename.php on line 69."
I then realized something; the reason for this came from the fact that I used $key, and $value for both of them in the exact same way.
As a response to this, I've developed two ways to fix this:
<?php
//add this to the end of every foreach() you use
unset($key,$value)
?>
OR
Simply use different variables for each one.
[Ed Note: You can also use array_keys() so that you don't have to have the $value_copy variable --alindeman at php.net]
I use the following to modify the original values of the array:
<?php
foreach ($array as $key=>$value_copy)
{
$value =& $array[$key];
// ...
$value = 'New Value';
}
?>
"As of PHP 5, you can easily modify array's elements by preceding $value with &. This will assign reference instead of copying the value."
There are cases where array_walk or array_map are inadequate (conditional required) or you're just too lazy to write a function and pass values to it for use with array_map...
My solution to foreach for php 4 and 5 to modify values of an array directly:
<?php
$testarr = array("a" => 1, "b" => 2, "c" => 3, "d" => 4);
$testarr_keys = array_keys($testarr);
$testarr_values = array_values($testarr);
for ($i = 0; $i <= count($testarr) - 1; $i++) {
$testarr[$testarr_keys[$i]] = $testarr_values[$i] * 2;
}
print_r($testarr);
?>
[quote]
I want to add some inline comments to dtowell's piece of code about the iteration by reference:
<?php
$a = array('abe','ben','cam');
foreach ($a as $k=>&$n)
$n = strtoupper($n);
# At the end of this cycle the variable $n refers to the same memory as $a[2]
# So when the second "foreach" assigns a value to $n :
foreach ($a as $k=>$n) // notice NO reference here!
echo "$n\n";
# it is also modifying $a[2] .
# So on the three repetitions of the second "foreach" the array will look like:
# 1. ('abe','ben','abe') - assigned the value of the first element to the last element
# 2. ('abe','ben','ben') - assigned the value of the second element to the last element
# 3. ('abe','ben','ben') - assigned the value of the third element to itself
print_r($a);
?>
[/quote]
To resolve this problem - should always use unset after foreach:
<?php
$array = array('abe','ben','cam');
foreach ( $array as $key=>&$val ) {}
unset($key); unset($val);
foreach ( $array as $key=>$val ) {}
unset($key); unset($val);
print_r($array);