Jump to content

[SOLVED] Strange Self-destructing loop?


SirGCal

Recommended Posts

Ok, here's a weird one that I came across trying to fix some OLD php...

 

Anyhow, I'm stuck with this particular format for this very involved program. But the array self destructs and I don't understand why... Here's a test snippet...

 

<?php
$list = array('t1', 't2');
$testarray['t1']['jdoe']['m1'] = 'test1';
$testarray['t1']['jdoe']['m2'] = 'test2';
$testarray['t2']['jdoe']['m1'] = 'test3';
$testarray['t2']['jdoe']['m2'] = 'test4';

// PRINT OUT THE OUTPUT
print "ATTEMPT1:<BR>\n";
foreach ($list as $p1) {
  print "$p1:\n";
  if (is_array($testarray[$p1])) {

// TRIED A FOREACH INSTEAD OF A WHILE, SAME RESULT
//    while (list($username, $val) = each($testarray[$p1])) {
    foreach ($testarray[$p1] as $username => $val) {
      print " - ". $val['m2']. ", ". $val['m1']. "\n";
      }
    }
  print "<BR>\n";
  }

// DO IT ALL AGAIN, EXPECT SAME OUTPUT
print "ATTEMPT2:<BR>\n";
foreach ($list as $p1) {
  print "$p1:\n";
  if (is_array($testarray[$p1])) {
    while (list($username, $val) = each($testarray[$p1])) {
      print " - ". $val['m2']. ", ". $val['m1']. "\n";
      }
    }
  print "<BR>\n";
  }
?>

 

The result from this code is simply:

 

ATTEMPT1:
t1: - test2, test1
t2: - test4, test3
ATTEMPT2:
t1:
t2:

 

But I expect:

 

ATTEMPT1:
t1: - test2, test1
t2: - test4, test3
ATTEMPT2:
t1: - test2, test1
t2: - test4, test3

 

Unfortunately, 5.2.3 is the newest PHP I have access too at the moment. (though the systems we're actually using unfortunately are much lower, still I've tried this on all with the same results). All I can figure is that it's something to do with the multi-level hash as a single level obviously doesn't do this. Any ideas? I've tried multiple ways of looping the second loop. That's the best spot I can figure that is causing this (you can see the while and foreach in the first loop group).

Link to comment
https://forums.phpfreaks.com/topic/158334-solved-strange-self-destructing-loop/
Share on other sites

Well so here's how it really breaks down.

 

When using foreach loop, it has an array internal pointer that tells it where it's at in the array. The foreach loop resets this internal pointer each time you traverses an array. Unfortunately, the each function does not. So after you ran foreach on the array and step right into a while loop using each, the internal pointer is at the end of the array so it would return false. If you change the while loop to a foreach, it would work. So how do you get it to work with the each function? Well, you will need to reset the array.

 

<?php
$list = array('t1', 't2');
$testarray['t1']['jdoe']['m1'] = 'test1';
$testarray['t1']['jdoe']['m2'] = 'test2';
$testarray['t2']['jdoe']['m1'] = 'test3';
$testarray['t2']['jdoe']['m2'] = 'test4';

// PRINT OUT THE OUTPUT
print "ATTEMPT1:<BR>\n";
foreach ($list as $p1) {
  print "$p1:\n";
  if (is_array($testarray[$p1])) {

// TRIED A FOREACH INSTEAD OF A WHILE, SAME RESULT
//    while (list($username, $val) = each($testarray[$p1])) {
    foreach ($testarray[$p1] as $username => $val) {
      print " - ". $val['m2']. ", ". $val['m1']. "\n";
      }
    }
  print "<BR>\n";
  }

// DO IT ALL AGAIN, EXPECT SAME OUTPUT
print "ATTEMPT2:<BR>\n";
foreach ($list as $p1) {
  print "$p1:\n";
  if (is_array($testarray[$p1])) {
    reset($testarray[$p1]);  // added this line
    while (list($username, $val) = each($testarray[$p1])) {
      print " - ". $val['m2']. ", ". $val['m1']. "\n";
      }
    }
  print "<BR>\n";
  }
?>

 

I commented on the line I added. I hope this helps. :)

 

Edit - it's similar to mysql_fetch_assoc and mysql_fetch_array.

Ahhhhhhh.....

 

I tried the foreach in the top, but not in both... This one is strange...

 

Why would the while or foreach work in the first no matter what. But the second one will only loop if it has the foreach in it (or the reset, thanks by the way...). Why does the foreach allow auto-reset but while doesn't... That's a bit confusing to me.. I'm a Perl guru but PHP I'm only average. I'm trying to understand the logic behind why this does/doesn't work.

 

So, to summarize:

 

Loop 1: while

Loop 2: while

Failed

 

Loop 1: foreach

Loop 2: while

Failed

 

Loop 1: while

Loop 2: foreach

Passed

 

Loop 1: foreach

Loop 2: foreach

Passed

 

Any combination with reset: passed...

 

Obviously, that tells me the reset is the proper method to use, but I'm still woundering why it works like above... If anyone knows that is...

 

As for how I got it to work with the each? That's just the first way I learned how to parse out hashes (associative arrays). So I default back to that instead of the foreach as => options. It, so far, has worked fine for me. Obviously though, I'm jumping in from a Perl and not PHP prospective so I guess my side is; I don't understand why the while/each group you would not expect to work... ? Please educate me on the details of the each that would block this...

 

Anyhow, THANKS so much for pointing me to a simple solution... :-)

Okay. As you traverse an array with either foreach or each functions (not sure if there are others), it increments the array internal pointer.

 

The foreach will increment this pointer as it traverses the array. Same for each. The only difference is that if you use foreach, it auto-resets the pointer at the start of the array before it starts traversing the array. each does not do this for you.

 

So with your cases above -

 

Case 1: If you use while ... each in the first iteration through the array, it does as you would think it would. But after that run, the array's internal pointer is at the very end of the array. Unless you reset this pointer, your second while loop run will do nothing because if you call each on the array again, it will return the value false because there are no more entries.

 

Case 2: Same case. foreach will set the array's internal pointer at the end of the array after its run and when the while ... each picks it up, it doesn't do anything.

 

Get it yet? It's not that the foreach resets and the while doesn't. It's that the foreach resets and each doesn't. In fact, if you take out the each part in the while loop, it works. Why is that? Well, my guess is that if you use foreach, you're traversing through the entire array at once. each doesn't traverse an array at all. It pulls an entry and increments the internal pointer. I guess you can say that under the right circumstances, they both have their uses. It just doesn't apply in your case.

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.