1

I've got a rather complicated set of loops that pulls data out of mysql and compares it to values in an array and increments a counter. When I echo a flag when the counter is incremented, I get a bijilion flags (there're like 2600 records returned from the mysql query). But each time it prints, the counters are always 1 and when I print the counter's value at the end, it shows up as zero. It seems like something is re-setting the counter…

code

# ARRAY
$demographics=array(
    "region"=>array(
        "Northeast"=>array('total'=>0,'consented'=>0,'completed'=>0),
         //more...
        "West"=>array('total'=>0,'consented'=>0,'completed'=>0)
    ),"societal envirn"=>array(
        "Urban"=>array('total'=>0,'consented'=>0,'completed'=>0)
    ),"age"=>array(
        '18-19'=>array('total'=>0,'consented'=>0,'completed'=>0),
        '20-24'=>array('total'=>0,'consented'=>0,'completed'=>0),
         //more...
        '55-59'=>array('total'=>0,'consented'=>0,'completed'=>0)
    ),
    //more...
);

# LOOPS
while ($dbrecord = mysql_fetch_assoc($surveydata)) {
    foreach ( $dbrecord as $dbfield=>$dbcellval ) {
        foreach ( $demographics as $demographic=>$options ) {
            foreach ( $options as $option=>&$counter ) {
                if($demographic==="age"){
                    list($min,$max) = explode('-', $option);
                    if ($dbcellval >= $min && $dbcellval <= $max){
                        $counter['total']++;
                        echo '$' . $option . "['total'] = " . $counter['total'] . "<br />";
                        if ($dbrecord['consent']==="1"){
                            $counter['consented']++;
                            echo '$' . $option . "['consented'] = " . $counter['consented'] . "<br />";
                            if ($dbrecord['completion status']==="complete") {
                                $counter['completed']++;
                                echo '$' . $option . "['completed'] = " . $counter['completed'] . "<br />";
                                break 3;
                            } // if
                        } // if
                        break 2;
                    }
                } // if age
                else if ($option===$dbcellval){
                    $counter['total']++;
                    echo '$' . $option . "['total'] = " . $counter['total'] . "<br />";
                    if ($dbrecord['consent']==="1"){
                        $counter['consented']++;
                        echo '$' . $option . "['consented'] = " . $counter['consented'] . "<br />";
                        if ($dbrecord['completion status']==="complete") {
                            $counter['completed']++;
                            echo '$' . $option . "['completed'] = " . $counter['completed'] . "<br />";
                            break 3;
                        } // if
                    } // if
                    break 2;
                } // else if $option==$dbcellval
            } // foreach $options
        } // foreach $demographics
    } // foreach $dbrecord
} // while

sample output

$40-44['total'] = 1
$White['total'] = 1
$35-39['total'] = 1
$Northeast['total'] = 1     // the 'total' counter is 1
$Northeast['consented'] = 1
$Northeast['completed'] = 1
$South['total'] = 1
$Northeast['total'] = 1     // notice the 'total' counter is 1 again :(
$Northeast['consented'] = 1
$Northeast['completed'] = 1
2
  • Is counter used or declared outside the loops? If not, its scope will be limited to the loop in which it's first used and reset each time that loop loops. Commented Sep 27, 2011 at 17:48
  • Hi Kevin, I'm pretty sure php doesn't scope like that. Commented Sep 27, 2011 at 18:12

3 Answers 3

2

You're defining counter from a foreach instruction, as $value in foreach($foo as $key=>$value), when using the foreach you only have a local copy of $counter.

You need to use either foreach($foo as $key=>&$value) or to refer to the full array path of your counter from $demographics.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi regilero, I tried adding the &, but didn't seem to help (I updated my code above to reflect what I did with the &). I don't think I can refer to the full path for the counter in $demographics because that's why I'm looping.
Ahh, after @dar7yl 's answer I see what you meant. Thanks!
1

You need to reference your array at each level, otherwise you are working on a copy of the data:

foreach ( $dbrecord as $dbfield=>$dbcellval ) {
    foreach ( $demographics as $demographic => &$options ) {
        foreach ( $options as $option => &$counter ) {
            if($demographic==="age"){
                list($min,$max) = explode('-', $option);
                if ($dbcellval >= $min && $dbcellval <= $max){
                    $counter['total']++;

Comments

-2

What if you simply stick with the $demographics variable.

i.e.

...
foreach ( $options as $option ) {
   ...
   $demographics[$option]['total']++;

...

5 Comments

Hi Ayman, thanks, but I'm already doing that (see the code I posted earlier). Each option (North, South) needs to have its own set of counters
If my theory is correct, your issue has to do with scope. You're creating the "$counter" variable for the first time after the loop has started. In other words, you're re-creating the "$counter" variable with every iteration of the loop.
@Ayman: php's variable scoping doesn't apply to loops. A variable used for the first time inside a loop will NOT get reset each iteration
Oh, well kind of, but $counter is not real. because of the foreach loop, $counter resolves to "region","age",etc so it's really age['total']. But just in case, I tried it, but it did not work.
@AymanSafadi, actually that kind of did something: the count isn't stuck at 1, but now I think it's just one set of counters instead of 38 sets.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.