...

View Full Version : key() Behavioral Differences PHP5.1.6 to PHP5.2.5



fuzzy1
05-07-2009, 03:56 AM
Hey all!
This little script works fine (iterating through MD array) in PHP5.2.5 on development server, but when I publish to production server (PHP5.1.6) it doesn't work (just loops through first sub "AL" -- over and over...). The problem appears to hinge on the line(s) "$new_state= key($cities);" but I can't figure out why, and am stumped as to an alternative.
HELP!:eek:
P.S. It's a complete example. Cut, Paste and give it a whirl !

<?php
$state="AL";//start value
$city="auburn";//start value
if($_GET['state']){
$state=$_GET['state'];
$city=$_GET['city'];
}
$cities= Array(
'AL' => Array (
'1' => Array ( 'city' => 'auburn', 'url' => 'http://auburn.mydomain.com/'),
'2' => Array ( 'city' => 'birmingham', 'url' => 'http://bham.mydomain.com/'),
'3' => Array ( 'city' => 'columbus, GA', 'url' => 'http://columbusga.mydomain.com/')//border town
),
'AK' => Array ( 'city' => 'anchorage', 'url' => 'http://anchorage.mydomain.com/'),
'AZ' => Array (
'1' => Array ( 'city' => 'flagstaff / sedona', 'url' => 'http://flagstaff.mydomain.com/'),
'2' => Array ( 'city' => 'mohave cnty', 'url' => 'http://mohave.mydomain.com/')
)
);

foreach($cities as $key=>$value){
if($key != $state){continue;}// iterate until it does...
$count= count($value);
if($value['city']==''){ //e.g. more than one city this state...
foreach($value as $c_num=>$c_val){
if($c_val['city']!=$city){continue;}
else{//OPTION A
if($c_num< $count){//e.g more cities this state
$condition= "A";
$i=$c_num+1;
$new_city = $value[$i]['city'];
$new_url = $value[$i]['url'];
break;
}
else{//NEW STATE -- OPTION B
$condition= "B";
$new_state = key($cities);//WORKS on PHP5.2.5 development server, but not in PHP5.1.6 production
$new_city = $cities[$new_state]['1']['city'];
$new_url=$cities[$new_state]['1']['url'];
if($new_city==''){//e.g only ONE city this new_state
$condition= "B1";
$new_city=$cities[$new_state]['city'];
$new_url=$cities[$new_state]['url'];
}
break;
}
}
}
}//end if more than one city this state...
else{//only ONE city this state...
$condition= "C";
$new_state = key($cities);//WORKS on PHP5.2.5 development server, but not in PHP5.1.6 production
$new_city = $cities[$new_state]['1']['city'];
$new_url=$cities[$new_state]['1']['url'];
if($new_city==''){
$condition= "C1";
$new_city=$cities[$new_state]['city'];
$new_url=$cities[$new_state]['url'];
}
break;
}
}//end foreach $cities
if($new_state=='')$new_state=$state;
echo "CONDITION =".$condition."<br>";
echo "Previous State=".$state."<br>";
echo "Previous City=".$city."<br>";
echo "New State=".$new_state."<br>";
echo "New City=".$new_city."<br>";
echo "<a href='test.php?state=$new_state&city=$new_city'>Next Iteration</a>";
?>

Hayyel
05-07-2009, 04:23 AM
Yep works on 5.2.9 perfectly. Sorry cant test older versions.

venegal
05-07-2009, 01:56 PM
From the PHP reference:

Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it.

So, making it referenced should solve your problem:

foreach($cities as $key => &$value)

fuzzy1
05-07-2009, 02:36 PM
Thanks venegal,
That did sound promising! Sadly no joy however.
Pointer still doesn't advance on 5.1.6 and on 5.2.5 the script breaks down completely at condition C :(

As opposed to resetting the pointer I HAD been looking (only half heartedly) for a means of setting (forcing ) the array pointer to a desired location, but no luck there either.

It's funny,
print_r(array_keys($cities)); returns Array ( [0] => AL [1] => AK [2] => AZ ), by which I would think I could then run a numeric iterator along side like
$i='0', $i++ if($condition) $new_state = $cities[$i] but alas a call to $cities[$i] only returns Array:o
I'm thinking it calls for a complete re-think but I've got that whole white-blind can't see the trees for the forrest thing going just now. Suggestions welcome!

venegal
05-07-2009, 02:48 PM
An easy fix would be to completely kick the foreach in favor of the (slower) manual each() loop.
So, try changing

foreach($cities as $key=>$value)
to


reset($cities);
while (list($key, $value) = each($cities))

This will definitely advance the array pointer.

Your last example can't work, because $i is no key of $cities, but you might try

$new_state = $cities[array_keys($cities)[$i]]

fuzzy1
05-07-2009, 04:39 PM
reset($cities);
while (list($key, $value) = each($cities))


Well....sort of? Let me offer a little context.
The start values are returned from a DB SELECT query, which is immediately followed by an UPDATE query
-- posting the new_values to the record to become the start values next time the script is called.
Some code is then executed on basis of the original start values, and we exit the script.

In this context, the call to reset($cities); would have to come only upon condition that the $city start value
exists at the end of the $cities array (last city value under last state sub-array).
Your suggestion works on the development server right up until we reach the end of the array.
Then it doesn't. I don't see a good way to determine weather or not the start value = end($cities).
Hmmmmm.......

venegal
05-07-2009, 07:10 PM
Acutally, reset($cities) is ok the way it is and needs to be called every time. All it does is set the array pointer to the start of the array, which is expected by your code. foreach does the same thing, only with each() you have to do it manually.

But I guess I understand now, what the problem is: You want the cities to loop through, so you get the first city of the first state as the next city, if the current city is the last one of the last state, right? And somehow with your approach it magically worked without having to care about it, because for some reason foreach in its unpredictability reset the array pointer to 0 once it reached the end, while each() expectedly does not.

If that's the case, just use each() and make sure to handle the end of the array properly. For example, change

$new_state = key($cities);
to

$new_state = key($cities) ? key($cities) : "AL";

fuzzy1
05-07-2009, 08:10 PM
If that's the case, just use each() and make sure to handle the end of the array properly. For example, change

$new_state = key($cities);
to

$new_state = key($cities) ? key($cities) : "AL";
correction: I DIDN'T see a good way to determine weather or not the start value = end($cities). NOW I DO! Cool!
Thanks venegal,
I'll give it a go and post my results here. Have to move on to other things for a bit now, but that sure beats my alternative solution of including a separate states array wherein $new_state= $states[$i]; (which now works, but is just plain ugly);)



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum