Диагностика
I подозреваю проблема в том, что $_pages
- это не обычный массив PHP, а объект, реализующий интерфейс Iterator
. Из-за этого «состояние» цикла foreach сохраняется в самом объекте, что означает, что эти два цикла конфликтуют.
Если бы $_pages
был простым массивом, то проблем не было бы, так как строка $pages = $this->production->getPages();
сделала бы копию , поскольку массивы PHP копируются при присваивании (в отличие от объектов), а также потому, что Вложенные циклы foreach
в обычном массиве не имеют этой проблемы. (Предположительно из некоторой внутренней логики копирования / назначения).
Решение
«Быстрое и грязное» исправление состоит в том, чтобы избегать циклов foreach, но я думаю, что это будет и раздражающим, и причиной будущих ошибок, потому что очень легко забыть, что $_pages
нуждается в супер-специальной обработке.
Для реального исправления я предлагаю посмотреть, какой класс находится за объектом в $_pages
, и посмотреть, сможете ли вы изменить этот класс. Вместо $_pages
быть Iterator
измените $_pages
, чтобы он предоставлял итераторов через интерфейс IteratorAggregate
.
Таким образом, каждый цикл foreach
запрашивает отдельный объект итератора и поддерживает отдельное состояние.
Вот пример сценария, иллюстрирующего проблему, частично взятый из справочных страниц PHP:
<?php
class MyIterator implements Iterator
{
private $var = array();
public function __construct($array)
{
if (is_array($array)) {
$this->var = $array;
}
}
public function rewind()
{
reset($this->var);
}
public function current()
{
$var = current($this->var);
return $var;
}
public function key()
{
$var = key($this->var);
return $var;
}
public function next()
{
$var = next($this->var);
return $var;
}
public function valid()
{
$key = key($this->var);
$var = ($key !== NULL && $key !== FALSE);
return $var;
}
}
// END BOILERPLATE DEFINITION OF ITERATOR, START OF INTERESTING PART
function getMyArrayThingy(){
/*
* Hey, let's conveniently give them an object that
* behaves like an array. It'll be convenient!
* Nothing could possibly go wrong, right?
*/
return new MyIterator(array("a","b","c"));
}
// $arr = array("a,b,c"); // This is old code. It worked fine. Now we'll use the new convenient thing!
$arr = getMyArrayThingy();
// We expect this code to output nine lines, showing all combinations of a,b,c
foreach($arr as $item){
foreach($arr as $item2){
echo("$item, $item2\n");
}
}
/*
* Oh no! It printed only a,a and a,b and a,c!
* The outer loop exited too early because the counter
* was set to C from the inner loop.
*/