 |
PHP 4 引入了 foreach 结构,和
Perl 以及其他语言很像。这只是一种遍历数组简便方法。foreach
仅能用于数组,当试图将其用于其它数据类型或者一个未初始化的变量时会产生错误。有两种语法,第二种比较次要但却是第一种的有用的扩展。
第一种格式遍历给定的 array_expression
数组。每次循环中,当前单元的值被赋给 $value
并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。
第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量
$key。
自PHP 5 起,还可能遍历对象。
注意:
当 foreach
开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在
foreach 循环之前调用 reset()。
注意:
除非数组是被引用,foreach
所操作的是指定数组的一个拷贝,而不是该数组本身。因此数组指针不会被
each()
结构改变,对返回的数组单元的修改也不会影响原数组。不过原数组的内部指针的确在处理数组的过程中向前移动了。假定
foreach 循环运行到结束,原数组的内部指针将指向数组的结尾。
自 PHP 5 起,可以很容易地通过在 $value 之前加上
& 来修改数组的单元。此方法将以引用赋值而不是拷贝一个值。
此方法仅在被遍历的数组可以被引用时才可用(例如是个变量)。
注意:
foreach 不支持用“@”来抑制错误信息的能力。
用户可能注意到了以下的代码功能完全相同:
以下代码功能也完全相同:
示范用法的更多例子:
juraj5
21-Jul-2007 06: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
?>
tquick at pixelated dot com
16-Jul-2007 03:08
It is worth noting that the following code works, and has helped me out quite a few times; not to mention saved time.
This may be obvious to some, but it just dawned on me that the following works:
<?php
foreach($_GET as $x) {
echo "$x <br />";
}
?>
Lets say we named this file, index.php
We put into the address bar:
/index.php?name=x&page=y&other=z
The code would output:
x
y
z
Luke at chaoticlogic dot net
02-Jul-2007 08: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.
kirk at proofed dot net
13-Jun-2007 11:09
Foreach by reference bug:
Can anyone explain this one to me? I've had similar problems with the way foreach handles values by reference. This is the simplest example I could come up with:
<?php
$array1 = array('a' => 1);
$array2 = array('b' => 2);
$array3 = array('c' => 3);
$matrix = array($array1, $array2, $array3);
foreach($matrix as &$array)
$array['d'] = 4;
foreach($matrix as $array)
print_r($array);
?>
This should just add the key / value pair ['d'] = 4 to each array.
The expected output is then:
Array ( [a] => 1 [d] => 4 ) Array ( [b] => 2 [d] => 4 ) Array ( [c] => 3 [d] => 4 )
The actual output is:
Array ( [a] => 1 [d] => 4 ) Array ( [b] => 2 [d] => 4 ) Array ( [b] => 2 [d] => 4 )
My guess:
The first foreach loop disrupts the pointer making the second foreach loop point to the last element twice.
Is anyone able to explain this better or create an even simpler example where this happens?
Jonny Arnold
23-Feb-2007 05:53
Note that you can use the break statement within a foreach loop, should you wish.
27-Jan-2007 06: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 09: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 04: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 04: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 08: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 07: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 08: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 07: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 06: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 03: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*.
Wout (BE)
24-Feb-2006 01:46
If you want to use an array, depending on a variable, you can point to it within a foreach function like this :
$language = EN;
$xyz_EN = array (...);
$xyz_NL = array (...);
foreach ( ${'xyz_'.$language} as ...)
{
...
};
Hermann
22-Feb-2006 01:55
foreach may be used not only to iterate through array elements, but also to iterate through object properties.
Documentation should specify that.
Edwin_fromUtrecht at NOSPAM dot example dot com
15-Feb-2006 02: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 01: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 06: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 05: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 10: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 04: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
*/
FatalError
21-Dec-2005 11:39
I recommend using a "while" instead of a "foreach," like this:
<?php
while (list($key, $val) = each($array)) {
// Do something...
}
?>
This gives you more control and gets rid of some problems that you may have with the foreach statement.
janezr at jcn dot si
10-Nov-2005 09: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]] ;
...
}
?>
boxer at racaboxer dot com dot br
09-Nov-2005 06:19
To do tables with cells alleatories...
<?
foreach($result as $item)
{
$x++;
if(($x % 2)==0) {
?>
<tr>
<td align='center' valign='middle' bgcolor='#FFFFFF' width='300'>
<img src="<?=$item['src'];?>" border="<?=$item['border'];?>" alt="<?=$item['alt'];?>">
</td>
<td align='center' valign='middle' bgcolor='#FFFFFF' width='300'>
<?=$item['obs'];?>
</td>
</tr>
<? } else { ?>
<tr>
<td align='center' valign='middle' bgcolor='#FFFFFF' width='300'>
<?=$item['obs'];?>
</td>
<td align='center' valign='middle' bgcolor='#FFFFFF' width='300'>
<img src="<?=$item['src'];?>" border="<?=$item['border'];?>" alt="<?=$item['alt'];?>">
</td>
</tr>
<?
}
}
?>
Just it !
Flavio Tubino From Blumenau, Brazil
07-Oct-2005 06:59
Like the FOR statement, you can also write:
<?php
$a_array=array("a","b","c");
foreach($a_array as $key=>$value):
print $key." = ".$value."<br>";
endforeach;
?>
Flavio From Brazil
07-Oct-2005 06:55
Like the FOR statement, you can also write:
<?php
foreach($i=1;$i<10;$i++):
print $i;
endforeach;
?>
retula AT gmail DOT com
05-Oct-2005 01:54
Here is a cool script to optimize all the tables in a database! (mysql only)
<?php
// connect to the db
mysql_connect("host","username","pw");
mysql_select_db("database");
//get all tables
$alletabellen = mysql_query("SHOW TABLES");
//go trough them, save as an array
while($tabel = mysql_fetch_assoc($alletabellen)){
//go through the array ( $db => $tabelnaam )
foreach ($tabel as $db => $tabelnaam) {
//optimize every table
mysql_query("OPTIMIZE TABLE `".$tabelnaam."`") or die(mysql_error());
}
}
?>
Enjoy!
Oto "Zver" Brglez ml.
24-Sep-2005 01: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>
dyer85 at gmail dot com
27-Jul-2005 10:44
Concerning mike's post below, the list and each function style would also work:
<?php
/* Tweak of Mike's original code */
/*
Additions include Friendly HTML format or normal
spaces for command line
*/
/*
May you never be forced to deal with a structure
like this in real life...
*/
$items = array(
-1,
0,
array(
array(1,2,3,4),
array(5,6,7,8),
array(9,10,11,12)
),
array(
array("a", "b", "c"),
array("d", "e", "f"),
array("g", "h", "i")
)
);
// HTML formatting
echo "<pre>\n"; print_array($items, 0); echo "</pre>\n";
function print_array($arr, $level)
{
$indent='';
// Change to false if you want CLI formatting (no entities)
$html=true;
// Hehe, I've always used 3-spaced tabs
$indent = $html ? str_repeat(' ', $level * 3) : $indent = str_repeat(' ', $level *3);
// Changed from foreach
while ( list(, $item) = each($arr) )
{
if (is_array($item))
{
echo $html ? $indent . "Item is an array...<br>\n" :
$indent . "Item is an array...\n";
print_array($item, $level+1);
}
else
{
echo $html ? $indent . "Value at current index: " . $item . "<br>\n" :
$indent . "Value at current index: " . $item . "\n";
}
}
}
?>
mikeb at tracersinfo dot com
26-Jul-2005 05: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".
magistrata at gmail dot com
13-Jul-2005 04: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 08: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
24-Jun-2005 10: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 03: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]);
}
}
}
mike at invertedmind dot com
17-Jun-2005 06:24
One great use of foreach is for recursive function calls. It can handle things that would otherwise need to be hand-coded down to the desired level, which can make for hard-to-follow nesting.
<?
/*
May you never be forced to deal with a structure
like this in real life...
*/
$items = array(
-1,
0,
array(
array(1,2,3,4),
array(5,6,7,8),
array(9,10,11,12)
),
array(
array("a", "b", "c"),
array("d", "e", "f"),
array("g", "h", "i")
)
);
print_array($items, 0);
function print_array($arr, $level)
{
$indent = str_repeat(" ", $level * 4);
foreach ($arr as $item)
{
if (is_array($item))
{
print $indent . "Item is an array...<br>\n";
print_array($item, $level + 1);
}
else
print $indent . "Value at current index: " . $item . "<br>\n";
}
}
?>
This will output:
Value at current index: -1
Value at current index: 0
Item is an array...
Item is an array...
Value at current index: 1
Value at current index: 2
Value at current index: 3
Value at current index: 4
Item is an array...
Value at current index: 5
Value at current index: 6
Value at current index: 7
Value at current index: 8
Item is an array...
Value at current index: 9
Value at current index: 10
Value at current index: 11
Value at current index: 12
Item is an array...
Item is an array...
Value at current index: a
Value at current index: b
Value at current index: c
Item is an array...
Value at current index: d
Value at current index: e
Value at current index: f
Item is an array...
Value at current index: g
Value at current index: h
Value at current index: i
And it could recurse as far as you want it to go.
30-May-2005 05: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.
dave at davedelong dot com
28-May-2005 10:42
A "cheap" way to sort a directory list is like so (outputs HTML, one indent is 3 non-breaking spaces):
<?php
function echo_Dir($dir, $level) {
//create an empty array to store the directories:
$dirs = array();
//if we were given a directory to list...
if (is_dir($dir)) {
//and if we can open it...
if ($handle = opendir($dir)) {
//change directory:
chdir($dir);
//iterate through the directory
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (is_dir($file)) {
//only add legit directories to the array
array_push($dirs,$file);
}//end if
}//end if
}//end while
//sort the array
sort($dirs);
//NOW handle each directory via a foreach loop
foreach ($dirs as $i => $file) {
$to_echo = str_repeat("\t",$level+1) . str_repeat(" ",$level*3) . $file . "<br>";
echo $to_echo;
echo_Dir($file,$level+1);
}//end foreach
//return to the parent directory
chdir("../");
}//end if
//close the handle
closedir($handle);
}//end if
}//end function
?>
For an example of what this outputs, check out http://www.davedelong.com/php/echodir.php
mark at myipower dot com
26-May-2005 02:10
Here is a solution to an earlier comment I found that worked well for me. It only goes 4 deep on a complex array or object but could go on forever I would imagine.
foreach($_SESSION as $value => $lable1){
echo "The elements of Value1 <B>" . $value . "</B> is <B>" . $lable1 . "</B><br/>\n";
if(is_array($lable1) || is_object($lable1)) {
foreach($lable1 as $value2 => $lable2){
echo "The elements of Value2 <B>" . $value2 . "</B> is <B>" . $lable2 . "</B><br/>\n";
if(is_array($lable2) || is_object($lable2)) {
foreach($lable2 as $value3 => $lable3){
echo "The elements of Value3 <B>" . $value3 . "</B>is <B>" . $lable3 . "</B><br/>\n";
if(is_array($lable3) || is_object($lable3)) {
foreach($lable3 as $value4 => $lable4){
echo "The elements of Value4 <B>" . $value4 . "</Bis <B>" . $lable4 . "</B>><br/>\n";
}
}
}
}
}
echo "<br>";
}
}
flobee at gmail dot com
21-May-2005 08: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 08: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.
wrm at metrushadows dot com
21-May-2005 05:10
Another example for printing out arrays.
<?php
$array = array(
1 => 'milk',
2 => 'eggs',
3 => 'bread'
);
foreach ($array as $array => $value) {
echo "$value<br />";
}
?>
fred at flintstone dot com
20-May-2005 04:40
<?
You can easily use FOREACH to show all POST and GET variables from a form submission
function showpost_and_get()
{
print "<hr><h2>POST</h2><br>";
foreach($_POST as $varName => $value)
{
$dv=$value;
$dv=$value;
print "Variable: $varName Value: $dv<br>";
};
print "<hr><h2>GET</h2><br>";
foreach($_GET as $varName => $value)
{
$dv=$value;
print "Variable: $varName Value: $dv<br>";
};
}
Paul Chateau
17-May-2005 06: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 05: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 05: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 08: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 08: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 03: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 03: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 07: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 01:43
It is possible to suppress error messages from foreach, using type casting:
<?
foreach((array)$myarr as $myvar) {
...
}
?>
turadg at berkeley dot edu
22-May-2004 12: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(
|