# foreach loops are sooooo tricky.....

#### Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

•  Subject
• Author
• Posted on
Just something I would like to share:

I just learned the hard way (2 days detective work on a bug) that foreach
loops are not at all like for loops, not intuitive at all. BEWARE: arrays
and matrices are sparse by design/definition in PHP.

I'm doing some matrix manipulation in a Finite Element program.
Translating Fortran to PHP, because hosters won't allow anything else
than PHP.
I wish PHP would do array and matrix stuff like Fortran or C, btw.
Something for PHP 6 ?
Check out this code:

\$k = array(1=>
array(1=>1,1,1,1,1,1),
array(2=>1,1,1,1,1),
array(3=>1,1,1,1),
array(4=>1,1,1),
array(5=>1,1),
array(6=>1));

/*
you would expect this to mirror the matrix about a diagonal from upper
left to lower right multiplying each coefficient by 2 on the way...
However, the foreach loop is tricky. */
foreach(\$k as \$i=>& \$_k)
foreach(\$_k as \$j=>&\$__k)
{
\$__k *= 2;
if (\$i != \$j)
\$k[\$j][\$i ] = \$__k;
}

foreach(\$k as &\$_k)
{
foreach(\$_k as &\$__k)
echo " \$__k ";
echo "<BR>";
}

echo "<BR>";

/* this is better: */

\$k = array(1=>
array(1=>1,1,1,1,1,1),
array(2=>1,1,1,1,1),
array(3=>1,1,1,1),
array(4=>1,1,1),
array(5=>1,1),
array(6=>1));

for (\$i=1; \$i <= 6; \$i++)
for (\$j=\$i; \$j<= 6; \$j++)
if (isset(\$k[\$i][\$j]))
{
\$k[\$i][\$j] *= 2 ;
if (\$i != \$j)
\$k[\$j][\$i] = \$k[\$i][\$j];
}
foreach(\$k as &\$_k)
{
foreach(\$_k as &\$__k)
echo " \$__k ";
echo "<BR>";
}
echo "<BR";
/*
*
*/
\$k = array(1=>
array(1=>1,1,1,1,1,1),
array(2=>1,6=>1),
array(3=>1,1,1,1),
array(4=>1,1,1),
array(5=>1,1),
array(6=>1));

for (\$i=1; \$i <= 6; \$i++)
for (\$j=\$i; \$j<= 6; \$j++)
if (isset(\$k[\$i][\$j]))
{
\$k[\$i][\$j] *= 2 ;
if (\$i != \$j)
\$k[\$j][\$i] = \$k[\$i][\$j];
}
foreach(\$k as &\$_k)
{
foreach(\$_k as &\$__k)
echo " \$__k ";
echo "<BR>";
}

## Re: foreach loops are sooooo tricky.....

Osiris wrote:

I find foreach loops to be quite intuitive.  However, your FORTRAN
naming conventions make your code very hard to understand, and I don't
have the time to try to figure out what you're trying to do.

Try using some descriptive names for your variables.  It will make your
code a lot easier to understand.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

## Re: foreach loops are sooooo tricky.....

On Sat, 01 Dec 2007 09:36:47 -0500, Jerry Stuckle wrote:

There is nothing to describe , really... this example is just about a
general matrix with numbers to be mirrored.

The issue here is, that in a foreach loop you can inadvertedly enter extra
coefficients in the matrix, that are processed in a next iteration.
A for loop determins exactly which coefficients to process. A foreach loop
processes all that it encounters, new or old.
Mind you: I know what the problem is with the code. I did not say PHP was
in error, just that foreach-es are not alway what you EXPECT them to
be.

## Re: foreach loops are sooooo tricky.....

Osiris wrote:

Well, a foreach loop is supposed to go through all of the elements.  So
I would expect it to also process additional elements if you add them in
the loop.

However, if you add extra elements to an array, the for loop will also
process them, i.e.

\$myArray[0] = 0;
for (\$i=0; \$i<count(\$myArray); \$i++) {
\$myArray[\$i+1] = \$i*2+2;
}

will run for a long time...

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex@attglobal.net
==================

## Re: foreach loops are sooooo tricky.....

Highly unlikely...  Given the PHP team's obsession with OOP, expecting
anything quant-friendly is an unrealistic hope.  OOP and numerical
computing don't mix too well...

At the same time, we have to keep in mind that Fortran has been around
for 50 years now, so the code base created over all that time is
incredibly rich, especially when it comes to numerical stuff.   At
some point, I needed a couple of statistical routines in PHP, so I
ended up porting them from Fortran code written circa 1970...

A possible way out would be to take "Numerical Recipes in C" (which is
a C clone of "Numerical Recipes in Fortran") and wrap those C
functions into a PHP extension, but it still wouldn't solve the
problem of availability on shared hosting...

Cheers,
NC

## Re: foreach loops are sooooo tricky.....

.

That's true, but I don't think that's the problem here.

I doubt it.  That's simply not its problem domain.

My guess is that it's not the foreach loop that is biting you, but rather
the references.

What does this produce for you?  Does the next-to-the-last line really do
what you think?  Is that making a copy of the value, or is it storing a
reference to the value?  That is, won't \$k[2][1] simply be a reference to
\$k[1][2], and not a separate value?

My only convenient server runs PHP 4, which does not support the reference
notation.  If I change your code to this, which I believe to be equivalent:

foreach(\$k as \$i=> \$_k)
foreach(\$_k as \$j=>\$__k)
{
\$__k *= 2;
\$k[\$i][\$j] = \$__k;
if (\$i != \$j)
\$k[\$j][\$i ] = \$__k;
}

the result is a 6x6 square array where every element is 2.
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

## Re: foreach loops are sooooo tricky.....

On Sun, 02 Dec 2007 00:53:06 +0000, Tim Roberts wrote:

this works ok, so the referencing is not the problem:
<?php
\$f = array(1=>array(5=>1,3=>2,8=>3),array(3=>2,4,5));
foreach(\$f as &\$_f)
foreach(\$_f as &\$__f)
echo \$__f." ";
for (\$i=1; \$i <= 6; \$i++)
{
for (\$j=1; \$j <= 6; \$j++)
echo \$k[\$i][\$j]." ";
echo "<BR>";
}

?>

The thing is, that while mirroring a coefficient, it may be processed
again in a next iteration.
At the start of the routine, there is an upper triangular matrix, but
next, some elements of the lower triangle are added, having BEEN doubled.
foreach apparently does a
complete search for new elements each loop. Correct , but it's a very
different mechanism than a for loop, which pinpoints each element to
process

Now for the even more weird thing:
running the above loops in eclipse debugger, I get this:
2 4 4 4 4 4
4 2 4 4 4 4
4 4 2 4 4 4
4 4 4 2 4 4
4 4 4 4 2 4
4 4 4 4 4 2

Running it in Firefox on my localhost (apache 2), i get this:

2 2 2 2 2 2
2 1 1 1 1 1
2 2 1 1 1 1
2 2 2 1 1 1
2 2 2 2 1 1
2 2 2 2 2 1

## Re: foreach loops are sooooo tricky.....

The issue is, that foreach loop process any element of a matrix that it
will encounter.
For loops only the indexed elements (i,j)
When mirroring the upper triangular matrix, I ADD elements.

But now for the really kinky thing: running the following routine on my
localhost(apache 2.2.3,PHP5), I get
2 2 2 2 2 2
2 1 1 1 1 1
2 2 1 1 1 1
2 2 2 1 1 1
2 2 2 2 1 1
2 2 2 2 2 1
Running it through the Eclipse PHP Zend debugger I get (which, in my
opinion, is right):
2 4 4 4 4 4
4 2 4 4 4 4
4 4 2 4 4 4
4 4 4 2 4 4
4 4 4 4 2 4
4 4 4 4 4 2

<?php
\$k = array(1=>
array(1=>1,1,1,1,1,1),
array(2=>1,1,1,1,1),
array(3=>1,1,1,1),
array(4=>1,1,1),
array(5=>1,1),
array(6=>1));
foreach(\$k as \$i=>& \$_k)
foreach(\$_k as \$j=>&\$__k)
{
\$__k *= 2;
if (\$i != \$j)
\$k[\$j][\$i ] = \$__k;
}

for (\$i=1; \$i <= 6; \$i++)
{
for (\$j=1; \$j <= 6; \$j++)
echo \$k[\$i][\$j]." ";
echo "<BR>";
}

?>

I make this a new thread, to get explanations.