SirGCal Posted May 15, 2009 Share Posted May 15, 2009 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 More sharing options...
Ken2k7 Posted May 15, 2009 Share Posted May 15, 2009 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. Link to comment https://forums.phpfreaks.com/topic/158334-solved-strange-self-destructing-loop/#findComment-835053 Share on other sites More sharing options...
SirGCal Posted May 15, 2009 Author Share Posted May 15, 2009 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... :-) Link to comment https://forums.phpfreaks.com/topic/158334-solved-strange-self-destructing-loop/#findComment-835056 Share on other sites More sharing options...
Ken2k7 Posted May 15, 2009 Share Posted May 15, 2009 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. Link to comment https://forums.phpfreaks.com/topic/158334-solved-strange-self-destructing-loop/#findComment-835059 Share on other sites More sharing options...
SirGCal Posted May 16, 2009 Author Share Posted May 16, 2009 Awesome Explanation! Thanks very much! Link to comment https://forums.phpfreaks.com/topic/158334-solved-strange-self-destructing-loop/#findComment-835061 Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.