PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

break> <for
Last updated: Fri, 10 Oct 2008

view this page in

foreach

Mit PHP 4 wurde ein foreach Konstrukt eingeführt, genau wie Perl und einige andere Sprachen. Diese ermöglicht es, auf einfache Weise ein Array zu durchlaufen. foreach funktioniert nur in Verbindung mit Arrays. Wenn Sie versuchen foreach mit Variablen eines anderen Datentyps oder nicht initialisierten Variablen zu benutzen, gibt PHP einen Fehler aus. Es gibt zwei Syntaxformen; die zweite ist eine unbedeutende, aber sinnvolle Erweiterung der ersten Syntax:

foreach (array_expression as $value) Anweisung
foreach (array_expression as $key => $value) Anweisung

Die erste Form durchläuft das array_expression-Array. Bei jedem Durchgang wird der Wert des aktuellen Elements $value zugewiesen und der interne Array-Zeiger um eins erhöht. Dadurch wird beim nächsten Durchgang automatisch das nächste Element ausgewertet.

Die zweite Form arbeitet genauso, außer dass bei jedem Durchlauf auch der aktuelle Schlüssel der Variablen $key zugewiesen wird.

Hinweis: Sobald foreach zum ersten Mal ausgeführt wird, wird der interne Arrayzeiger automatisch auf das erste Element des Arrays gesetzt. Das bedeutet, dass Sie vor einem Durchlauf von foreach reset() nicht aufrufen müssen.

Hinweis: Beachten Sie auch, dass foreach mit einer Kopie des angegebenen Arrays arbeitet, nicht mit dem Array selbst. Deshalb wird auch der Arrayzeiger nicht wie bei dem each()-Konstrukt verändert und Veränderungen an ausgegebenen Arrayelementen haben keine Auswirkung auf das originale Array. Trotzdem wird der interne Arrayzeiger des originalen Arrays bei der Verarbeitung bewegt. Angenommen, die foreach-Schleife ist komplett abgearbeitet, wird der interne Arrayzeiger (des originalen Arrays) auf das letzte Element zeigen.
Beginnend mit PHP 5 können Sie die Arrayelemente einfach ändern wenn Sie der $value Variable ein & voranstellen. Hierdurch werden die Elemente per reference zugewiesen und nicht als Kopie des Wertes.

<?php
$arr 
= array(1234);
foreach (
$arr as &$value) {
    
$value $value 2;
}
// $arr ist nun array(2, 4, 6, 8)
?>
Dies ist nur möglich wenn das Array referenziert werden kann (d.h. veränderbar ist).

Hinweis: Bei foreach ist es nicht möglich Fehlermeldungen durch den Gebrauch von '@' zu unterdrücken ist

Beachten Sie, dass die folgenden Beispiele in ihrer Funktionalität identisch sind:

<?php
$arr 
= array("eins""zwei""drei");
reset ($arr);
while (list(, 
$value) = each ($arr)) {
    echo 
"Wert:  $value<br />\n";
}

foreach (
$arr as $value) {
    echo 
"Wert:  $value<br />\n";
}
?>
Auch hier funktioniert alles gleich:
<?php
$arr 
= array("eins""zwei""drei");
reset ($arr);
while (list(
$key$value) = each ($arr)) {
    echo 
"Schlüssel: $key; Wert: $value<br />\n";
}

foreach (
$arr as $key => $value) {
    echo 
"Schlüssel: $key; Wert: $value<br />\n";
}
?>

Noch einige Beispiele, die die Anwendung verdeutlichen:

<?php
/* foreach Beispiel 1: Nur der Wert */

$a = array(12317);

foreach (
$a as $v) {
   echo 
"Aktueller Wert von \$a: $v.\n";
}

/* foreach Beispiel 2:
Wert (mit Ausgabe des Arrayschlüssels zur Veranschaulichung) */

$a = array(12317);

$i 0/* nur zu Veranschaulichung */

foreach($a as $v) {
    echo 
"\$a[$i] => $v.\n";
    
$i++;
}

/* foreach Beispiel 3: Schlüssel und Wert */

$a = array(
    
"eins" => 1,
    
"zwei" => 2,
    
"drei" => 3,
    
"siebzehn" => 17
);

foreach(
$a as $k => $v) {
    echo 
"\$a[$k] => $v.\n";
}

/* foreach Beispiel 4: multidimensionale 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 Beispiel 5: dynamische Arrays */

foreach (array(12345) as $v) {
    echo 
"$v\n";
}
?>



break> <for
Last updated: Fri, 10 Oct 2008
 
add a note add a note User Contributed Notes
foreach
Robin Leffmann
26-Sep-2008 03:51
It should be noted that when using foreach to pass an array's key ($key => $value), the key must be a string and not binary content - containing 0's, f.e., as was my case when i used foreach to parse bencoded data handed back to me from a bittorrent tracker scraping - as this will throw foreach off and hand you a key that is binary different than the actual content of the array.
rhi
17-Sep-2008 12:22
If you use foreach with references, don't forget to unset the reference if you are not sure that a later piece of code doesn't use the same variable name. Example:

$latest_tutorials = $db->queryAll("select * from tutorials"...);
foreach ($latest_tutorials as &$tut)
    $tut["comments"] = $db->queryOne("select count(*) ...");
// ...
$tut = $db->queryRow("...");

print_tutorials($latest_tutorials);
print_tutorial($tut);

Here the last entry of latest_tutorials will be replaced by the row that is fetched by the $tut = $db->queryRow("..."); line because $tut is still referencing the last array entry. Solution:

foreach ($latest_tutorials as &$tut)
    $tut["comments"] = $db->queryOne("select count(*) ...");
unset($tut);
// ...
$tut = $db->queryRow("...");
brian at diamondsea dot com
15-Aug-2008 05:15
A common problem is having PHP generate an error when trying to iterate through an array that may sometimes have no data in it.  This causes PHP to generate a warning such as:

Warning: Invalid argument supplied for foreach() in test.php on line 14

You can prevent this error by type-casting the foreach variable as an array type using "(array)" before the array variable name.

<?php
// double any value whose key starts with 'b'
$arr = array('a'=>1, 'b1'=>2, 'b2'=>3, 'c'=>4, 'd'=>5);
$non_array = null;

// Normal usage with an array
print "Test 1:\n";
foreach (
$arr as $key => $val) {
    print
"Key $key, Value $val\n";

}

// Normal usage with a non-array (undefined or otherwise empty data set)
// Outputs: Warning: Invalid argument supplied for foreach() in test.php on line 16
print "Test 2:\n";
foreach (
$non_array as $key => $val) {
    print
"Key $key, Value $val\n";
}

// By casting the $non_array to an (array) type, it will function without error, skipping the loop
print "Test 3:\n";
foreach ((array)
$non_array as $key => $val) {
    print
"Key $key, Value $val\n";
}

print
"Done.\n";

?>

Outputs:

Test 1:
Key a, Value 1
Key b1, Value 2
Key b2, Value 3
Key c, Value 4
Key d, Value 5
Test 2:

Warning: Invalid argument supplied for foreach() in /home/bgallagher/test.php on line 16
Test 3:
Done.
php_manual at SPAMNONE dot jessemccarthy dot net
08-Jun-2008 10:10
In PHP 4, foreach is broken when used on an undefined array element (see http://bugs.php.net/bug.php?id=41169 ):

<?php

$example
= array();

foreach (
$example[ 'element' ] as $value ) {

}

var_dump( $example );

?>

Expected output:
array(0) {
}

Actual output:
array(1) {
  ["element"]=>
  NULL
}

I think this is probably the least painful workaround:

<?php

$example
= array();

foreach ( (array)
$example[ 'element' ] as $value ) {

}

var_dump( $example );

?>

Output:
array(0) {
}
adam dot sindelar at gmail dot com
14-Apr-2008 03:45
You can also use the alternative syntax for the foreach cycle:

foreach($array as $element):
  #do something
endforeach;

Just thought it worth mentioning.
kevin at metalaxe dot com
15-Mar-2008 02:46
In response to marian at devourmedia dot com 28-Feb-2008 05:34:

That's why you use reference modifier on the value:

foreach($t as $var=> &$val)
    $val = 'K';
marian at devourmedia dot com
29-Feb-2008 02:34
Also, do not forget that foreach is not useful
if you change the value inside of the loop.

For example:
$t=array('a', 'a', 'a', 'a', 'a', 'a', 'a', '1', 'a', 'a', 'a', 'a', 'a');
foreach($t as $var=>$val)
{
$t=array();
echo "val={$val}<br>";
}

is still showing the contents of the array $t.
chris at deskpro dot com
22-Nov-2007 01:46
I would suggest that people making distributable scripts do not rely on foreach working on a copy. People using some opcode caches (or script encoding like ioncube) appear to break this. While this is a bug in the opcode cache, it might be prudent to not rely on this 'feature'.
henrik at newdawn dot dk
28-Oct-2007 12:08
As stated further up the foreach is consuming a lot of memory if used within large arrays - that is - if the array consists of for instance large objects. I had a case where a foreach caused me to run out of the 256 MB memory that PHP is allowed to handle - but changing to a for() statement completly removed both memory and CPU load.
tcrosby at gmail dot com
27-Aug-2007 03:37
Using the much-maligned ability of foreach to work on references rather than copies, it becomes possible to recurse indefinitely into deep arrays without the need to know beforehand how deep they go.  Consider the following example (which I use to sanitize input):

<?php

// Sanitize as a function to allow recursing; original array passed by reference
function sanitize(&$array) {
        foreach (
$array as &$data) {
                if (!
is_array($data)) { // If it's not an array, clean it
                       
$data = '\\' . $data; // addslashes(), mysql_real_escape_string() or whatever you wish to use, this is merely a simple example
               
}
                else {
// If it IS an array, call the function on it
                       
sanitize($data);
                }
        }
}

// Test case
$test = array(
                array(
                        array(
                               
0,
                               
1,
                               
2
                       
),
                       
3,
                       
4
               
),
               
5,
               
6
       
);

// Output
sanitize($test);
print_r($test);

/*

Output:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => \0
                    [1] => \1
                    [2] => \2
                )

            [1] => \3
            [2] => \4
        )

    [1] => \5
    [2] => \6
)

*/

?>

When first called on $test, it passes a reference to the original $test array to the sanitize function, which begins to iterate through its contents with the immediate foreach loop.  Each value that is not in itself an array gets sanitized as normal, and as both the foreach loop and the function itself are acting by reference, all changes happen directly to the contents of the superglobal rather than to copies.  If the value given IS an array, it then calls the same function on it.  The key here is that both the function and the foreach loop work by reference, meaning that you can call the calling function while in the foreach loop and all changes are still applied to the original array, without corruption of the array pointer, as it remains intact for each level of the array.  When the end of an array is reached, the function simply returns; if it was a deeper-level array, the parent function (and parent foreach loop) continue as they were; if the top-level loop ends, then the function returns to the main code, having acted on the entire array.  As everything operates within the scope of the sanitize function, you even avoid the danger of leaving the last reference set, as $data is not available outside the scope of the function in which any particular loop operates.  While this might sound complicated at first, the result is that by passing to foreach by reference, true indefinite recursion is possible.
john factorial
16-Aug-2007 09:49
In response to gherson's method of foreach'ing over a string's characters, PHP 5 now provides you with the str_split() function.

So, to foreach through the characters of a string in PHP 5:

<?php
$string
="string";
$array = str_split($string);
foreach(
$array as $char) print($char."<br/>");
?>

This outputs:
s
t
r
i
n
g
juraj5
21-Jul-2007 08:51
The place where the manual says that foreach and while constructs using list and each are functionally completely identical is not true.

Consider a block of code where you need to push an additional into an array while it's being iterated. As foreach is running on a copy of the array, it will only iterate through entries that were in the array when foreach was started. The other method will iterate through all entries.

Code demo:

<?php

$array
= array('i', 'v', 'a', 'n');

foreach(
$array as $key=>$value) {
if(
implode('', $array) == 'ivan') $array[]='a';
echo
$value; } // prints out ivan

array_pop($array);

reset($array);
while (list(
$key, $value) = each($array)) {
    if(
implode('', $array) == 'ivan') $array[]='a';
    echo
$value; } // prints out ivana
?>
Luke at chaoticlogic dot net
02-Jul-2007 10:08
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.
27-Jan-2007 07:50
Here is an obvious question to most of the readers, but it took me about two precious minutes to figure out, so I figured I will share it will you:

What will be the output of the following statement:
<?php
$data
= array('1' => 'field1', '2' => 'field2');
foreach (
$data as $field_index => $field_name);
{
    echo
"$field_name";
}
?>
Correct answer is 'field2', and not 'field1field2'. The forgotten semicolon at the foreach line does not trigger a syntax error, but php treats it as an empty statement..

and then the block is run once with the last value set into $field_name.
joaohbruni at yahoo dot com dot br
25-Jan-2007 10:24
Iterate through an array of objects, and change property values from original object.

My original code only worked in PHP5:

foreach($array as $element) {
  $element->property = "new_value";
}

Solution for both PHP4 and PHP5:

reset($array);
while (list($key, $value) = each($array)) {
  $element =& $array[$key];
  $element->property = "new_value";
}
GPatmore
17-Jan-2007 05:29
In reference to the comment by Timon Van Overveldt...

Although your suggestion works for changing the original array, a copy of the original array is still created for nothing.  This may become a performance issue when used with a large array. 

It has been suggested that if your code must be php4 compatible, use the alternative list()...each() style explained above to iterate through an array if you don't need to use a copy.
Timon Van Overveldt
15-Jan-2007 05:41
Why not just do this?

<?php
$arr
= array(1, 2, 3, 4);
foreach (
$arr as $i => $value) {
  
$arr[$i] = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
?>

No need for references, so it works in both PHP4 and PHP5.
simplex
19-Dec-2006 09:12
"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);
?>
robycar at libero dot com
07-Dec-2006 08:04
some useful functions for testing boolean values

<?php
$trueValues
= array('1', 'true', 't', 'y', 'yes', 'vero', 'v'); //edit with locale values
$falseValues = array('0', 'false', 'f', 'n', 'no', 'falso'); //edit with locale values

function str_to_bool($str) {
  foreach (
$GLOBALS['trueValues'] as $value)
      if (
strcasecmp($str, $value) == 0)
          return
true;
    foreach (
$GLOBALS['falseValues'] as $value)
      if (
strcasecmp($str, $value) == 0)
          return
false;
    return
NULL;
}

function
str_is_true($str) {
  return (
str_to_bool($str) === true);
}

function
str_is_false($str) {
  return
str_to_bool($str) === false;
}

/* Test */
str_to_bool('false'); //return false
str_to_bool('vero'); // return true
str_to_bool('php'); //return null
str_is_true('php'); //return false
str_is_false('php'); //return false

?>
support at mediaart dot ru
20-Jul-2006 10:46
php at kormoc dot com 11-May-2006 10:25 wrote:
With foreach and references, there is a super easy way to corrupt your data.

But you can avoid it by destruction of the hard link $item

<?php
$array
= array(1,2,3);
foreach(
$array as &$item );
unset(
$item);
foreach(
$array as $item );
print_r( $array );
?>
gherson
30-May-2006 09:33
To "foreach" over the characters of a string, first "preg_split" the string into an array:
<?php
$string
="string";
$array = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
foreach(
$array as $char) print($char."<br/>");
?>
This outputs:
s
t
r
i
n
g
php at kormoc dot com
11-May-2006 08:25
With foreach and references, there is a super easy way to corrupt your data

see this test script:
<?php
$array
= array(1,2,3);
foreach(
$array as &$item );
foreach(
$array as $item );
print_r( $array );
?>

You would imagine that it would have 1,2,3 but in reality, it outputs 1,2,2

The issue is that $item is a pointer to the last array value, and exists outside of the scope of the foreach, so the second foreach overwrites the value. If you would check what it gets set to in the second foreach loop, you would see that it gets set to 1 and then 2 and then 2 again.

This has already been filed as a bug, see:
http://bugs.php.net/bug.php?id=29992

but php developers seem to think that it's expected behaviour and *good* behaviour, so it's doubtful that it will change anytime soon. This is a really bad gotcha, so watch out.
php_man_resp at earthshod dot co dot uk
09-Mar-2006 04:58
To atroxodisse:  This behaviour is normal.  PHP arrays are associative arrays but, unlike Perl, with artificial order maintenance.  Keys can be any scalar value except references; of course integers are scalars, so traditional integer-indexed arrays just work.  {You can even have fractions in array indices, as long as you enclose the index in speech marks, such as $array["1.5"]!  This is not unique to PHP, by the way, but existed by accident in some dialects of BASIC seen on 1980s-vintage home computers.}  The foreach loop iterates over keys in chronological order of when they were added to the array, which is *not* necessarily the same as the sort order.  The print_r() function uses the same iteration order.

If you want to add elements to the beginning of an existing numeric array  {or between existing elements -- either using fractional indices, or because you left gaps when populating the array}  and have foreach iterate over them in order, then you will need to use ksort() on the array *first*.
Edwin_fromUtrecht at NOSPAM dot example dot com
15-Feb-2006 03:39
To comment on the foreach statement behaviour comment below: The reason for this different behaviour is that the foreach statement is equivalent to the each statement. They both make use of an internal pointer. To loop through the complete array after a change you could use the reset statement on the array.
atroxodisse at gmail dot com
10-Feb-2006 02:04
I just noticed something.  I created an array, Looped through a mysql result with a while and added values to that array with an index that I incremented manually, starting at position 1.  After closing the while loop I added an element at position 0 of the array.  When I looped through that array with a foreach loop it evaluated the elements starting from the first element that was added instead of starting at position 0.  I'm not sure if that was intentional but it does not seem to be in the documentation.  So in this case looping through the array with a foreach was not the same as looping through it with a for loop like this:

for($i =0; $i<count($myarray); $i++)

To anyone coming from a C or C++ background this might be confusing.
daniel dot oconnor at gmail dot com
09-Feb-2006 07:42
Dangers with References

<?php
$months
= array("Jan", "Feb", "March");

foreach (
$months as &$month) {
   
$month .= "Beep";
}

print_r($months);

foreach (
$months as $month) {
   
printf("%s\n", $month);

}

?>

Because $month is a reference to $months[2], iterating again with the same varible name causes $months[2] to be overwritten! Oh no!

Ouput:
Array
(
    [0] => JanBeep
    [1] => FebBeep
    [2] => MarchBeep
)
JanBeep
FebBeep
FebBeep
egingell at sisna dot com
31-Jan-2006 06:26
That is definitely weird.

Anyway, I found out that if you put something like $ary[] in where either the key and/or the value goes, you'll append all the keys and/or values to that array. Example:

<?php

$array
= array(
     
'num1' => 'a',
     
'num2' => 'b',
     
'num3' => 'c'
);

$k = array();
$v = array();

foreach (
$array as $k[] => $v[]);

echo
'$k => ' . print_r($k, true);
echo
'$v => ' . print_r($v, true);

?>

The above code will do this:

$k => Array (
      [0] => num1
      [1] => num2
      [2] => num3
)
$v => Array (
      [0] => a
      [1] => b
      [2] => c
)
RabidDog
17-Jan-2006 11:17
Pretty weird but for future reference

//doesn't multiply the last value
foreach ($ar as &$v){
    $v *= 2;
}
foreach($ar as $v){
    echo $v. "<br>"; 
}
//works fine
foreach ($ar as &$o){
    $o *= 2;
}
foreach($ar as $v){
    echo $v. "<br>"; 
}
pinheirosp at hotmail dot com
26-Dec-2005 05:25
In reply to FatalError, if you use Zend Dev Studio, i'll notice it's report "while(list() = each())" calls as "Using While w/ arrays param". So far, it's may be ambiguous to make things like that.

Prefer to make a clean code and use PHP "kernel" functions to navigate through an array.

Btw, if we take the exec time as example:

//a litte array, just to test =-]
$arr = array();
for($i=0; $i<100000; $i++) $arr[$i] = $i;

//list-each solution
$myTime = microtime(true);
reset($arr);
while (list($key, $value) = each($arr)) {
   $value = ($key * $value);
}
$myTime = microtime(true) - $myTime;
echo("list-each : " . $myTime . "<BR />\n");

//foreach solution
$myTime = microtime(true);
foreach ($arr as $key => $value) {
   $value = ($key * $value);
}
$myTime = microtime(true) - $myTime;
echo("foreach : " . $myTime . "<BR />\n");

/*
output:

list-each : 0.40198588371277
foreach : 0.23317384719849
*/
janezr at jcn dot si
10-Nov-2005 10:06
If you want to "look-ahead" values in an associative or non-continuous array, this might help:

<?
$myArray
= {'one'=>1,'two'=>2,'five'=>5,'three'=>3}

$all_keys = array_keys($myArray);
foreach (
$all_keys as $key_index => $key ) {
 
$value =& $myArray[$key];
 
// $all_keys[$key_index+2] gives null if we go past the array boundary - be carefull there
 
$value2 =& $myArray[$all_keys[$key_index+2]] ;
  ...
}
?>
Oto "Zver" Brglez ml.
24-Sep-2005 03:14
You can use you'r own function for creating xml/html tags.

Function :
function tag($tag,$string,$atrib = false){
    if(!is_array($atrib)){
        return "<".$tag.">".$string."</".$tag.">";
    } else {
        $o = "<".$tag;
        foreach($atrib as $key => $val){
            $o .= " ".$key."=\"".$val."\"";
        };
        $o .= ">".$string."</".$tag.">";
        return $o;
    };
}

Usage:
$array[href] = "http://www.php.net";
$array[id] = "testcss";
$array[class] = "simplecssclass";

print(tag("a","PHP Home Page,$array));

Output:
<a href="http://www.php.net" id="testcss" class="simplecssclass">PHP Home Page</a>

You can use this function without attributes. Like this:
print(tag("b",Bold text));

Output:
<b>Bold text</b>
mikeb at tracersinfo dot com
26-Jul-2005 07:18
Using PHP5's foreach "as reference" can bite you!

Three guys in my office spent about a day chasing this one's tail, that was causing aberrant behavior in the values of elements of an array.  It turns out to be a consequence of the nature of references, generally.

If you create a reference to a variable, all names for that variable (including the original) BECOME REFERENCES.  To paraphrase "The Highlander," if you want a name to OWN a piece of data, "there can be only one."

To illustrate this point, consider the following code:

<?php

$f
= array(
      
0 => array('value' => 'three'),
      
1 => array('value' => 'three')
     );

foreach (
$f as $k => &$v ) {
 
$v['value'] = 'one';
}

$a = $f;
$b = $f;

$b[0]['value'] = 'two';
$b[1]['value'] = 'two';

var_dump($a, $b);

?>

Upon execution, you will find that, although you would expect $a to contain two arrays with 'value' of 'one', $a and $b are identical -- i.e., the changes of []['value'] to 'two' have happened in both arrays.  But, upon further examination of the var_dumps, you will see that both sets' elements [0] and [1] are preceded with "&":  they are references!

The easy solution to this problem turns out to be:  unset the foreach "as-reference" variable ($v) at the bottom of your foreach loop.  This allows the original variable (or array member) to resume ownership of the value and dissolves its "reference-ness".
chris at randomcat dot co dot uk
19-Jul-2005 10:19
Just as a note - it's generally not enough to just foreach through $_POST or $_GET, then addslashes() (although this often works)... you could be exposing yourself to a bit of nastiness due to magic quotes.

See the discussion example 3 of mysql_real_escape_string, for a bit more info: http://uk.php.net/manual/en/function.mysql-real-escape-string.php
magistrata at gmail dot com
13-Jul-2005 06:59
I use this code to do a simple cleanup on information heading from an HTML form into a database:

<?php
 
foreach ($_POST as $key => $value) {
    $
$key = addslashes(trim($value));
  }
?>
barnacle83-phpnotes at yahoo dot com
30-Jun-2005 10:06
Here are various ways I've seen to iterate arrays by reference in PHP4.
Based on my tests, I have placed them in order of fastest to slowest.

Benchmarking tool I used:
http://phplens.com/phpeverywhere/phpe-2004.htm#a3297
http://phplens.com/lens/dl/JPBS.zip

<?php
// --------------------------------------------------------------------

foreach ( array_keys($myArray) as $key ) {
 
$element =& $myArray[$key];
  ...
}

// --------------------------------------------------------------------

foreach( $myArray as $key => $element ) {
 
$element =& $myArray[$key];
  ...
  unset(
$element);
}

// --------------------------------------------------------------------

reset($myArray);
while ( list(
$key) = each($myArray) ) {
 
$element =& $myArray[$key];
  ...
  unset(
$element);
}
?>

Andrew
25-Jun-2005 12:00
The poster who submitted this loop style for iterating over variables by reference:

<?php
foreach( $object_list as $id => $the_object ) {
 
$the_object = &$object_list[$id]; // Re-assign the variable to point to the real object
  // ...
 
unset($the_object); // Break the link to the object so that foreach doesn't copy the next one on top of it.
}
?>

Using foreach() means you end up making a copy of the value, and then quickly reassign it to be a reference. This is a waste of the original copy operation.

You may want to consider this, more meaningful and readable alternative:

<?php

reset
($object_list);

while (list(
$key) = each($object_list)) {

  
$the_object = & $object_list[$key]; // Re-assign the variable to point to the real object

   // ...

  
unset($the_object); // Break the link to the object so that foreach doesn't copy the next one on top of it.

}
?>
JaGx
18-Jun-2005 05:55
On the note of Paul's for loop:
function foo($x) {
   global $arr; // some Array
   for($i=0; $i < count($arr); $i++) {
     if($arr[$i][0] == $x) {
         echo $arr[$i][1]."\n";
         foo($arr[$i][0]);
     }
   }
}

------------
The middle part of the for loop is evaluated every time it loops which means the count function is called as many times as it loops. It's always better (performance/speed wise) to put the count as the initialization code:

function foo($x) {
   global $arr; // some Array
   for($i=count($arr)-1;; $i>=0; $i++) {
     if($arr[$i][0] == $x) {
         echo $arr[$i][1]."\n";
         foo($arr[$i][0]);
     }
   }
}
30-May-2005 07:17
How To Use References In Foreach Safely And Sanely In PHP 4.

There are two really really important points to remember about foreach and references:
1. foreach makes a copy
2. references (and unset!) work by directly manipulating the symbol table

In practice, this means that if you have an array of objects (or arrays) and you need to work on them *in-place* in a foreach loop, you have to do this:

<?php
foreach( $object_list as $id => $the_object ) {
  
$the_object = & $object_list[$id]; // Re-assign the variable to point to the real object
  
....
   unset(
$the_object); // Break the link to the object so that foreach doesn't copy the next one on top of it.
}
?>

This really works. I have used it in dozens of places. Yes, you need it all, including the unset(). You will get extremely hard-to-find bugs if you leave out the unset().

Static.
flobee at gmail dot com
21-May-2005 10:32
be aware! take the note in the manual serious: "foreach operates on a copy of the specified array"
when working with complex systems you may get memory problems because of all this copies of arrays.

i love this function (easy to use) and use it more often than "for" or "while" functions but now i have really problems on this and finally found the reason (which can be a mess to find out)!
the sum of memory usage sometimes can be *2 than you really need.
flobee at gmail dot com
21-May-2005 10:31
be aware! take the note in the manual serious: "foreach operates on a copy of the specified array"
when working with complex systems you may get memory problems because of all this copies of arrays.

i love this function (easy to use) and use it more often than "for" or "while" functions but now i have really problems on this and finally found the reason (which can be a mess to find out)!
the sum of memory usage sometimes can be *2 than you really need.
Paul Chateau
17-May-2005 08:01
I had the same problem with foreach() and a recursiv function. If you don't want to spend about 1 or 2 hours to solve this problem, just use for() loops instead of foreach().
Some Example:

$arr[] = array(1,"item1");
$arr[] = array(2,"item2");
$arr[] = array(1,"item3");
//$arr[] = ...

//doesn't work
function foo($x) {
   global $arr; // some Array
   foreach($arr as $value) {
      if($value[0] == $x) {
         echo $value[1]."\n";
         foo($value[0]);
      }
   }
}

//just use this
function foo($x) {
   global $arr; // some Array
   for($i=0; $i < count($arr); $i++) {
      if($arr[$i][0] == $x) {
         echo $arr[$i][1]."\n";
         foo($arr[$i][0]);
      }
   }
}

Paul
badbrush at pixtur dot de
15-May-2005 07:22
another WARNING about report #26396 having status "wont fix":

Beware of using foreach in recursive functions like...

function sort_folders(&$items, $parent,$level) {
   foreach($items as $item) {
      if($item->parent == $parent) {

          print $item;
          // call recursively...
          sort_folders(&$items, $item, $level+1);
       }
   }
}
         
I struggled a few hours with this code, because I thought the passing the array by reference would be the problem. Infact you can only have ONE foreach for an array at any given time. A foreach inside another foreach does not work.

The manual should definately give some hints about this behaviour.

 pixtur
Elvin
23-Apr-2005 10:10
I wrote this code to add each post from a user to every users' txt file. But it only adds the message to the last user in users.txt. The reason of that is...(questmark)

<?php
session_start
();
header("Cach-control:private");

$name=$_SESSION['name'];

$nameframe=$name.".txt";
$message=$_POST['message'];

$wierdchars = array("\'", "\"", "\\", ":-)", ":-D", ":-p", ":-(", "=p", ">:0", ":-[", ":-/", ":-\\", ":-X", ":-?", "B-)");

$newchars = array (stripslashes("\'"), stripslashes("\""), "\\", "<img src='smile.gif'>", "<img src='opensmile.gif'>", "<img src='tounge.gif'>", "<img src='sad.gif'>", "<img src='tounge.gif'>", "<img src='yelling.gif'>", "<img src='embarrased.gif'>", "<img src='sosoleft.gif'>", "<img src='sosoright.gif'>", "<img src='quiet.gif'>", "<img src='confused.gif'>", "<img src='cool.gif'>");

$newmessage=str_replace($wierdchars, $newchars, $message);

$fontcolor=$_POST['fontcolor'];

$fontsize=$_POST['fontsize'];

$fontface=$_POST['fontface'];

$users=file("users.txt");

foreach(
$users as $user)
 {
$nameframed=$user.".txt";
$thefile=file_get_contents($nameframed);
$file=fopen($nameframed, "w+");
$body=$name."|".$newmessage."\n";
$body2=$body.$thefile;
$write=fwrite($file,$body2);
fclose($file);
 }
echo
"<html><head><title>Adding info...</title>";
echo
"<script>window.location='frame.php';</script>";
echo
"</head>";
echo
"<!--Removes ads form page</head><body>";
?>
18-Mar-2005 09:05
It seems that foreach returns different variable types depending on which syntax you use and which version of PHP you are running.

If you use this syntax:

        foreach($array as  $key => $val) {

then the $val variable is a string (or whatever the actual value in the array is).

But if you use this syntax:

        foreach($array as  $val) {

then it appears that the $val variable is an array in PHP 4.3.10, and it is a string (or whatever) in versions 4.3.1, 4.3.2, and 4.3.6 (I haven't tested any other version).
14-Dec-2004 04:29
This is a summary of bug report #26396 having status "wont fix", so the following is not a bug (report), but may need extra highlighting so the novice programmer (like me) can make sense of the second note given above.

Note:  Also note that foreach operates on a copy of the specified array and not the array itself. Therefore, the array pointer is not modified as with the each() construct, and changes to the array element returned are not reflected in the original array. However, the internal pointer of the original array is advanced with the processing of the array. Assuming the foreach loop runs to completion, the array's internal pointer will be at the end of the array.

<?
$myArray
= array("a", "b");

foreach(
$myArray as $anElement) {
  foreach(
$myArray as $anotherElement) {
    echo
$anotherElement;
  }
}
?>

results in "abab", as each foreach works on a copy of $myArray.

However:

<?
$myArray
= array("a", "b");

function
b() {
  global
$myArray;
 
  foreach(
$myArray as $anotherElement) {
    echo
$anotherElement;
  }
}

function
a() {
  global
$myArray;
 
  foreach(
$myArray as $anElement) {
   
b();
  }
}

a();
?>

results in "ab", ie. both foreach work on the same instance of $myArray because it is referenced as a global variable. Nevertheless, to the casual observer both variants seem equivalent and therefore should produce the same output.
gardan at gmx dot de
07-Oct-2004 09:21
(PHP 5.0.2)
Pay attention if using the same variable for $value in both referenced and unreferenced loops.

$arr = array(1 => array(1, 2), 2 => array(1, 2), 3 => array(1, 2));
foreach($arr as &$value) { }
foreach(array(1,2,3,4,5) as $value) { }
echo $test[3];

What happens here is that after the first foreach() loop, you have in $value a reference to the last element of $arr (here: array(1, 2)).

Upon entering the second foreach(), php assigns the value. Now value is assigned to where $value (which is still a reference) points, that is, the last element of $arr.

Your output will be "5", not the expected "Array". To be on the safe side, unset($value) before entering the next foreach().
turadg at berkeley dot edu
22-May-2004 02:19
The documentation above says "the internal pointer of the original array is advanced with the processing of the array".

In my experience, it's more complicated than that.  Maybe it's a bug in 4.3.2 that I'm using.

If the array variable is created by =& assignment, then it works as described.  You can use current() within the loop to see the next element.

If the array variable is created by an = assignment, the foreach() doesn't advance the pointer.  Instead you must use next() within the loop to peek ahead.

The code below demonstrates.  On my system, the output is the same for both blocks, though one uses next() and the other current().

<?php
$originalArray
= array("first", "second", "third", "fourth", "fifth");

print
"the array:\n";
print_r($originalArray);

print
"\noriginalArray with next():\n";
foreach (
$originalArray as $step) {
   
$afterThis = next($originalArray);
    print
"$step,$afterThis\n";
}

$aliasArray =& $originalArray;

print
"\naliasArray with current():\n";
foreach (
$aliasArray as $step) {
   
$afterThis = current($aliasArray);
    print
"$step,$afterThis\n";
}
?>
scott at slerman dot net
18-Apr-2004 05:27
Apparently the behavior of foreach with classes changed in PHP5. Normally, foreach operates on a copy of the array. If you have something like

<?php
foreach ($array as $value){
   
$value = "foo";
}
?>

the original array will not be modified. However, testing this code on PHP5RC1

<?php

class foobar {
   
    var
$a;
    var
$b;
   
    function
foobar(){
       
$this->a = "foo";
       
$this->b = "bar";
    }
}

$a = new foobar;
$b = new foobar;
$c = new foobar;

$arr = array('a' => $a, 'b' => $b, 'c' => $c);

foreach (
$arr as $e){
   
$e->a = 'bah';
   
$e->b = 'blah';
}

var_dump($arr);

?>

resulted in the following output:

array(3) {
  ["a"]=>
  object(foobar)#1 (2) {
    ["a"]=>
    string(3) "bah"
    ["b"]=>
    string(4) "blah"
  }
  ["b"]=>
  object(foobar)#2 (2) {
    ["a"]=>
    string(3) "bah"
    ["b"]=>
    string(4) "blah"
  }
  ["c"]=>
  object(foobar)#3 (2) {
    ["a"]=>
    string(3) "bah"
    ["b"]=>
    string(4) "blah"
  }
}

It would seem that classes are actually passed by reference in foreach, or at least that methods are called on the original objects.
jazfresh at hotmail dot com
18-Feb-2004 07:50
There is a really really big pitfall to watch out for if you are using "foreach" and references.

Recall this example:
<?
$a
= "Hello";
$b =& $a;   // $b now refers to "Hello"
$b = "Goodbye"; // BOTH $a and $b now refer to "Goodbye"
?>

This also applies to the loop variable in a foreach construct. This can be a problem if the loop variable has already been defined as a reference to something else.

For example:
<?
// Create some objects and store them in an array
$my_objects = array();
for(
$a = 0; $a < $num_objects; $a++) {
 
$obj =& new MyObject();
 
$obj->doSomething();
 
$my_objects[] =& $obj;
}

// later on in the same function...
foreach($my_objects as $obj) { // Note that we are trying to re-use $obj as the loop variable
 
$obj->doSomethingElse();
}
?>

When the "for" loop exits, $obj is a reference to the last MyObject that was created, which is also the last element in the "my_objects" array.

On every iteration, the foreach loop will do the equivalent of:

<?
$obj
= $my_objects[$internal_counter++];
?>

$obj will now refer to the appropriate element in the array.

But recall the reference example at the top. Because $obj was already defined as a reference, any assignment to $obj will overwrite what $obj was referring to. So in other words, on every foreach loop iteration, the last element in the array will be overwritten with the current array element.

To avoid this problem, either use a differently named loop variable, or call "unset()" on the loop variable before you begin the foreach().

It would be more intuitive PHP unset() the loop variable before a foreach began, maybe they'll put that in a later version.
andy at barbigerous dot net
06-Feb-2004 07:05
For dual iteration, the internal pointers may need resetting if they've been previously used in a foreach.

<?PHP

for(
    
$someArray1.reset(),
    
$someArray2.reset();
     list(,
$someValue1 ) = each( $someArray1 ) ,
     list(,
$someValue2 ) = each( $someArray2 )
     ;
) {

 echo
$someValue1;
 echo
$someValue2;

}

?>
php at electricsurfer dot com
22-Apr-2003 10:33
[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';
}
?>
ian at NO_SPAM dot verteron dot net
02-Jan-2003 12:29
Note that foreach is faster than while! If you can replace the following:

<?php
reset
($array);
while(list(
$key, $val) = each($array))
{
 
$array[$key] = $val + 1;
}
?>

...with this (although there are functional differences, but for many purposes this replacement will behave the same way)...

<?php
foreach($array as $key => $val)
{
 
$array[$key] = $val + 1;
}
?>

You will notice about 30% - 40% speed increase over many iterations. Might be important for those ultra-tight loops :)
17-Sep-2002 06:06
"Also note that foreach operates on a copy of the specified array, not the array itself, therefore the array pointer is not modified as with the each() construct and changes to the array element returned are not reflected in the original array."

In other words, this will work (not too expected):
foreach ($array as $array) {
    // ...
}

While this won't:
while (list(, $array) = each($array)) {
    // ...
}

break> <for
Last updated: Fri, 10 Oct 2008
 
 
show source | credits | sitemap | contact | advertising | mirror sites