PHP: переменная область в нескольких foreach - PullRequest
1 голос
/ 16 декабря 2010

EDIT:
Проблема решена с помощью $ i + 1 при вызове функции.

У меня проблемы с использованием переменных в нескольких foreaches. Проблема возникает, когда я пытаюсь вызвать функцию внутри foreach. Всякий раз, когда я делаю это, значение итератора основного цикла внезапно становится равным нулю (независимо от того, на каком круге он включен), но когда я закомментирую вызов функции, значение итератора будет отображаться, как и должно быть снова.

Может ли кто-нибудь указать мне правильное направление в доступе к переменным в следующих примерах:

Это работает как надо

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 
        }
    }
}

Но это не работает, итератор отображается как 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, а не о правильном порядке имен или чего-то подобного. Я просто обеспокоен тем, почему значение $ i внезапно меняется. Может быть, моя логика, но убедитесь сами

(при использовании $ i или $ b в функции addName () вывод $ i равен 000000000012, при использовании $ a вывод $ i внезапно меняется на 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();

Ответы [ 6 ]

5 голосов
/ 16 декабря 2010

foreach петли не имеют собственной области видимости.

Способ работы:

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 достигает 1.

1 голос
/ 16 декабря 2010

Не настоящий ответ, но ваш код на самом деле такой же, как:

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

Вы уверены, что эта логика верна?Что ты хочешь делать?Не зная, что делает addStuff, кажется немного странным добавлять одно и то же значение трижды с другим индексом к чему-либо.

Вот пример с вызовом метода:

$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);

        }
    }
}

который печатает (как и ожидалось):

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

Так что ошибка должна быть где-то еще .

0 голосов
/ 16 декабря 2010
<?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);
        }
    }
}

Я не вижу проблем с выполнением этого кода здесь: http://www.ideone.com/HsVDj

0 голосов
/ 16 декабря 2010

я добавил вашу переменную $something как 2d Array

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

Используя это, ваш foreach показывает очень хорошо:

000000011111112222222
0 голосов
/ 16 декабря 2010

Во втором примере $i будет равным 0 для первой итерации базового цикла.

Он останется равным 0 для всех $something с и всех $value с, затем перейдет к следующей базовой итерации, установив $i в 1 и т. Д. *

0 голосов
/ 16 декабря 2010

Я не уверен, но это может быть связано с тем, что $i определено в цикле for(). Я бы попробовал определить $i непосредственно перед тем, как определен цикл for().

Джеймс

...