|
|
 |
PHP 4 introduced a foreach construct, much
like Perl and some other languages. This simply gives an easy way to
iterate over arrays. foreach works only on arrays, 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; the
second is a minor but useful extension of the first:
The first form loops over the array given by
array_expression. On each loop, the value of
the current element is assigned to $value and
the internal array pointer is advanced by one (so on the next
loop, you'll be looking at the next element).
The second form does the same thing, except that the current
element's key will be assigned to the variable
$key on each loop.
As of PHP 5, it is possible to
iterate objects too.
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.
Note:
Unless the array is referenced,
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.
As of PHP 5, you can easily modify array's elements by preceding
$value with &. This will assign
reference instead of copying
the value.
This is possible only if iterated array can be referenced (i.e. is
variable).
Note:
foreach does not support the ability to
suppress error messages using '@'.
You may have noticed that the following are functionally
identical:
The following are also functionally identical:
Some more examples to demonstrate usages:
User Contributed Notes
foreach
Paul Chateau
17-May-2005 01: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 12: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
Michael T. McGrew
12-May-2005 12:11
This can be used to creat a list of urls for a nav bar or links section etc. If you draw the values of array from a mysql database it can be very usefull.
<?php
$arr = array(news, events);
foreach ($arr as $value) {
echo "<tr><td>Manage <a href=\"./".$value.".php\">".$value."</a></td></tr>";
}
?>
will return
<tr>
<td>Manage <a href="./news.php">news</a>
</td>
</tr>
<tr><td>Manage <a href="./events.php">events</a>
</td>
</tr>
Elvin
23-Apr-2005 03: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>";
?>
ldv1970
26-Mar-2005 07:53
18-Mar-2005 02: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).
xardas@spymac com
19-Feb-2005 09:35
Quote:
-------------------------
It makes sense, since you cannot call only keys from an array with foreach().
-------------------------
Why not?
<?php
foreach(array_keys($array) as $string)
{
print 'array key is '.$string;
}
?>
14-Dec-2004 09: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 02: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().
Scarab <scarab_at_scarab_dot_name>
29-Jun-2004 08:43
It is possible to suppress error messages from foreach, using type casting:
<?
foreach((array)$myarr as $myvar) {
...
}
?>
turadg at berkeley dot edu
21-May-2004 07: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
17-Apr-2004 10: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 12: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 = "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:
<?
$my_objects = array();
for($a = 0; $a < $num_objects; $a++) {
$obj =& new MyObject();
$obj->doSomething();
$my_objects[] =& $obj;
}
foreach($my_objects as $obj) { $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 12: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;
}
?>
thomas dot kaarud at netcom dot no
03-Feb-2004 07:41
A more elegant way to do this, without involving new arrays or making PHP5-specific code, would be:
<?php
foreach ($a as $x => $a) {
echo "$b[$x] : $a"; }
?>
Joseph Kuan
14-Jan-2004 11:42
<?php
Or use array_combine.
$c = array_combine($a, $b)
foreach($c as $aKey => $bVal) {
echo $aKey;
echo $bVal;
}
?>
endofyourself at yahoo dot com
01-Jan-2004 05:36
If you are trying to do something like:
<?PHP
foreach(
$someArray1 as $someValue1 ,
$someArray2 as $someValue2
) {
echo $someValue1;
echo $someValue2;
}
?>
Pleas note that this IS NOT possible (although it would be cool). However, here is another way to acheive a similar effect:
<?PHP
for(
;
list(, $someValue1 ) = each( $someArray1 ) ,
list(, $someValue2 ) = each( $someArray2 )
;
) {
echo $someValue1;
echo $someValue2;
}
?>
php at electricsurfer dot com
22-Apr-2003 03: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
01-Jan-2003 05: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 11: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)) {
// ...
}
| |