Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

EDIT:
Problem solved by using $i+1 in function call.

I have trouble using variables in multiple foreaches. The problem commeth when I try to call a function inside foreach. Whenever I do this the main loop's iterator value is suddenly zero (no matter which lap it's on) but when I comment out the function call the iterator value shows as it should again.

Could someone point me to the right direction in accessing variables in following examples:

This works as it shoulds

for($i=0; $i<3; $i++)
{
    echo $i; // 1, 2, 3
    foreach($something as $value)
    {
        echo $i; // main loop's iterator value
        foreach($value as $moreSomething)
        {
            echo $i; // main loop's iterator value 
        }
    }
}

But this doesn't work, iterator shows up as a 0.

for($i=0; $i<3; $i++)
{
    echo $i; // 1, 2, 3
    foreach($something as $value)
    {
        echo $i; // 0
        foreach($value as $moreSomething)
        {
            echo $i; // 0
            $object->addStuff($i, $moreSomething); // i = 0, moreSomething is correct
        }
    }
}

EDIT: I'm adding example code to reproduce the problem. Note that this is about the behaviour of $i's value, not the correct order of the names or something like that. I'm just concerned as why the $i's value suddenly changes. Might be my logic, but see for yourself

(when using $i or $b in addName() function $i's output is 000000000012, when using $a then $i's output suddenly changes to 00000000001111111222)

class RockPaperScissors
{
    private $nameArray;

  // constructor
  function RockPaperScissors () 
  {
    $this->nameArray = array();
  }

  function addName($level, $name)
  {
    $this->nameArray[$level][] = $name;
  }

  function getNames($level)
  {
    $array = array();
    foreach ($this->nameArray as $key => $value)
    {
        if ($key == $level)
        {
            foreach ($value as $name)
            {
                $array[] = $name;
            }
        }
    }
    return $array;
  }

  function printArray()
  {
    print_r($this->nameArray);
  }
}

function getNewNames($name)
{
    $array = array();
    switch ($name)
    {
        case "Mickey":
            $array[] = "Morty";
            $array[] = "Ferdie";
            break;

        case "Donald":
            $array[] = "Houie";
            $array[] = "Dewey";
            $array[] = "Louie";
            break;

        case "Goofy":
            $array[] = "Gilbert";
            break;

        case "Morty":
            $array[] = "Morty-B";
            break;

        case "Ferdie":
            $array[] = "Ferdie-B";
            break;

        case "Houie":
            $array[] = "Houie-B";
            break;

        case "Dewey":
            $array[] = "Dewey-B";
            break;

        case "Louie":
            $array[] = "Louie-B";
            break;

        case "Gilbert":
            $array[] = "Gilbert-B";
            break;
    }

    return $array;
}

$MAX_LEVELS = 3;
$RPS = new RockPaperScissors();
$RPS->addName(0, "Mickey");
$RPS->addName(0, "Donald");
$RPS->addName(0, "Goofy");

$a = 0;
$b = 0;
for ($i=0; $i<$MAX_LEVELS; $i++)
{
    $namesFromRPS = $RPS->getNames($i);
    echo $i;
    foreach($namesFromRPS as $name)
    {
        echo $i;
        $newNames = getNewNames($name);
        foreach($newNames as $newName)
        {         
            echo $i;
            // try switching $i to $a or $b and notice the behaviour change of $i
            $RPS->addName($i, $newName);
        }
        $a++;
    }
    $b++;
}

//$RPS->printArray();
share|improve this question
    
So you get an output of 1, 2, 3, 0, 0? That would be very odd, and hard to believe. –  Pekka 웃 Dec 16 '10 at 10:37
    
You are effectively calling $object->addStuff($i, $moreSomething); for each $moreSomehting three times, every time with a different $i. Maybe you logic is wrong. What do you want to achieve? –  Felix Kling Dec 16 '10 at 10:47
    
Could you show what addStuff is doing? –  Felix Kling Dec 16 '10 at 11:02
    
@pekka the output is more like 0000000000012 when it doesn't work and 0000000000111112222222 when it works. examples are a bit simplified, I'm sorry but I can show the whole code, but I could write up something to reproduce it. the addStuff only adds the value to object's private array with $this->arrayname[] = $moreSomething. –  Seerumi Dec 16 '10 at 11:14
    
0000000000111112222222?? If it would work, every number should as often as the others. 1 seems to appear less often. –  Felix Kling Dec 16 '10 at 11:21

6 Answers 6

up vote 6 down vote accepted

foreach loops do not have their own scope.

The way this is expected to work is:

Set $i to 0
 Enter the first foreach loop with `$i = 0`
  Enter the second foreach loop with `$i = 0`

Set $i to 1
 Enter the first foreach loop with `$i = 1`
  Enter the second foreach loop with `$i = 1`

etc.

I'll bet a beer that the loops work as expected, but there is nothing to do for the inner loops when $i reaches 1.

share|improve this answer
    
oh, that might be true –  Seerumi Dec 16 '10 at 12:33
    
My head is still a bit fuzzy of all the loop rotations, but I'm fairly sure that this is the case. thanks :P –  Seerumi Dec 16 '10 at 12:47
    
+1 for pointing on foreach has not own scope. –  2astalavista Jul 16 '13 at 16:06
<?php

$something = array(
    "one"   => array("oneMore1", "oneMore2", "oneMore3"),
    "two"   => array("twoMore1", "twoMore2", "twoMore3"),
    "three" => array("thrMore1", "thrMore2", "thrMore3"));

for($i = 0; $i < 3; $i++)
{
    echo "FIRST LOOP: " . $i;
    echo "\n";
    foreach($something as $value)
    {
        echo "SECOND LOOP: " . $i;
        echo "\n";
        foreach($value as $moreSomething)
        {
            echo "THIRD LOOP: " . $i;
            echo "\n";
            //$object->addStuff($i, $moreSomething);
        }
    }
}

I see no problem executing this code here: http://www.ideone.com/HsVDj

share|improve this answer

Not a real answer, but your code is actually the same as:

foreach($something as $value)
{
    foreach($value as $moreSomething)
    {
        for($i=0; $i<3; $i++)
        {
            $object->addStuff($i, $moreSomething); // i = 0, moreSomething is correct
        }
    }
}

Are you sure this logic is correct? What do you want to do? Not knowing what addStuff is doing, it seems a bit odd to add the same value three times with another index to something.

Here is an example with a method call:

$something = array(array(1,2), array(1,2));

class F {
   public function b($i, $value) {
       echo 'In function: i: ' . $i . ' value: ' . $value . PHP_EOL;
   }
}

$f = new F();

for($i=0; $i<3; $i++)
{
    echo "in for: " . $i . PHP_EOL; // 1, 2, 3
    foreach($something as $value)
    {
        echo "in 1. foreach: " . $i . PHP_EOL;
        foreach($value as $moreSomething)
        {
            echo "in 2. foreach: " . $i . PHP_EOL;
            $f->b($i, $moreSomething);

        }
    }
}

which prints (as expected):

in for: 0
in 1. foreach: 0
in 2. foreach: 0
In function: i: 0 value: 1
in 2. foreach: 0
In function: i: 0 value: 2
in 1. foreach: 0
in 2. foreach: 0
In function: i: 0 value: 1
in 2. foreach: 0
In function: i: 0 value: 2
in for: 1
in 1. foreach: 1
in 2. foreach: 1
In function: i: 1 value: 1
in 2. foreach: 1
In function: i: 1 value: 2
in 1. foreach: 1
in 2. foreach: 1
In function: i: 1 value: 1
in 2. foreach: 1
In function: i: 1 value: 2
in for: 2
in 1. foreach: 2
in 2. foreach: 2
In function: i: 2 value: 1
in 2. foreach: 2
In function: i: 2 value: 2
in 1. foreach: 2
in 2. foreach: 2
In function: i: 2 value: 1
in 2. foreach: 2
In function: i: 2 value: 2

So the error must be somewhere else.

share|improve this answer

I'm not sure, but it could be something to do with the fact that $i is defined within the for() loop. I'd try defining $i just before the for() loop is defined.

James

share|improve this answer
    
Nope, this will have no effect. $i is defined in the for loop, that is enough –  Pekka 웃 Dec 16 '10 at 10:52
    
This doesn't help. I've tried using $a = 0; before the base for-loop and ++'ing it at the end of the base loop, but it aswell shows as 0 –  Seerumi Dec 16 '10 at 10:57

i added your variable $something as a 2d Array

$something = Array(1 => Array(1 => "1", 2 => "2"), 2 => Array(3 => "3", 4 => "4"))

Using this, your foreach shows just fine:

000000011111112222222
share|improve this answer

In your second example, $i will be 0 for the first iteration of the base loop.

It will stay set to 0 for all $somethings and all $values, then it will move on to the next base iteration, setting $i to 1 and so on...

share|improve this answer
    
yes that's what it should do, but it stay's as 0 whatever the base loop's iteration is. when the base iteration's count goes to 1 the iterator in foreaches still stays as 0 and that's the problem. this occurs ONLY when I try to use it in a function. –  Seerumi Dec 16 '10 at 10:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.