[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Локален ли указатель в foreach?
redreem
Забавный случай:

Есть массив $cats - копия таблицы довольно распространенной структуры хранения категорий: (id,parent,name...).

На локальном хосте (PHP 5.2.6) прекрасно работал код:

function getCatsC($pId) {
global $cats;

foreach ($cats as $k=>$v) {
if ($v['parent']==$pId) {
//линк ребенка
}
}

}


function getCatsP($rootId) {
global $cats;

foreach ($cats as $k=>$v) {
if ($v['parent']==$rootId) {
//линк родителя
getCatsC($k);//запуск линка детей
}
}

}


getCatsP(0);


т.е. тупой перебор родителей-детей с линковкой их в нужную HTML структуру.

Заливаю на хостинг (PHP 5.1.6) - линкует только первого родителя и его детей.
Благо проблему нашел быстро, но ее смысл меня несколько обескуражил.
Дело в том, что оказалось, что в foreach циклах внутренний указаталь на локалке был локальным, а на хосте стал глобальным! т.е. при вызове линковки детей сбивался указатель для родительского цикла!

Для тех, кто подумал, что я думаю что они подумали - ссылка: http://www.php.su/learnphp/cs/?cycles#foreach с таким вот текстом:
Цитата
Внимание: Цикл foreach оперирует не исходным массивом, а его копией.
.

Т.е. мне пришлось просто переписать код так:

$cats2=$cats;

function getCatsC($pId) {
global $cats2;

foreach ($cats2 as $k=>$v) {
if ($v['parent']==$pId) {
//линк ребенка
}
}

}


function getCatsP($rootId) {
global $cats;

foreach ($cats as $k=>$v) {
if ($v['parent']==$rootId) {
//линк родителя
getCatsC($k);//запуск линка детей
}
}

}


getCatsP(0);


ну и сей казус объяснить кроме как тем, что это очередной ляп в php-реализациях - я ничем не могу.

Помогите!!! Сон потерял!!! :D



Спустя 9 минут, 5 секунд (23.09.2011 - 11:49) Sanchopansa написал(а):
Может проще передать этот массив как параметр функции и не париться?
типа:
function getCatsC($pId, $cats) {

foreach ($cats as $k=>$v) {
if ($v['parent']==$pId) {
//линк ребенка
}
}

}


function getCatsP($rootId, $cats) {

foreach ($cats as $k=>$v) {
if ($v['parent']==$rootId) {
//линк родителя
getCatsC($k, $cats);//запуск линка детей
}
}

}


getCatsP(0, $cats);

Спустя 1 минута, 55 секунд (23.09.2011 - 11:51) redreem написал(а):
я и не парюсь smile.gif проблема решена уже как я писал. смысл на каждом родителе передавать лишний параметр? дело в другом - почему вообще такая проблема возникла???

Спустя 1 час, 46 минут, 28 секунд (23.09.2011 - 13:37) linker написал(а):
Проблема не в PHP, проблема в изначально неверном алгоритме.

Спустя 12 минут, 25 секунд (23.09.2011 - 13:50) redreem написал(а):
я не прошу обсуждать алгоритм. давайте не будем отвечать на те вопросы, на которые мы сами хотим ответить. тема во флейме, поэтому либо по существу ситуации либо вообще лучше не писать. smile.gif

Спустя 2 минуты, 52 секунды (23.09.2011 - 13:53) redreem написал(а):
linker, алгоритм нормальный. я же не показал всего кода, там на 100 строк в каждой функции еще понаписано. раз такой способ я применил - значит мне так нужно.

Спустя 1 час, 8 минут, 25 секунд (23.09.2011 - 15:01) redreem написал(а):
для проверки:


getCats();
$GLOBALS['console']->addData($cats);


function getCatsC($pId) {
global $cats;

foreach ($cats as $k=>$v) {
if ($v['parent']==$pId) {
$GLOBALS['console']->addData($v);//выводим ребенка
}
}
}


function getCatsP($rootId) {
global $cats;

foreach ($cats as $k=>$v) {
if ($v['parent']==$rootId) {
$GLOBALS['console']->addData($v);//выводим родителя
getCatsC($k);//запуск линка детей
}
}
}


getCatsP(0);

Спустя 2 минуты, 3 секунды (23.09.2011 - 15:03) redreem написал(а):
и еще раз проблема: в foreach указатель должен быть локальным для каждого раза! а он на хостинге оказывается глобальным!

Спустя 3 часа, 26 минут, 48 секунд (23.09.2011 - 18:30) redreem написал(а):
up. неужели нет гипотез?

Спустя 5 часов, 6 минут, 47 секунд (23.09.2011 - 23:37) kirik написал(а):
Вообще довольно странно, ибо:
Цитата (http://php.net/manual/en/control-structures.foreach.php)
Note:

When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.

Но можно попробовать перед самим циклом вставить reset().

Спустя 3 минуты, 58 секунд (23.09.2011 - 23:41) redreem написал(а):
да, но как быть вот с этим утверждением:

http://www.php.su/learnphp/cs/?cycles#foreach с таким вот текстом:
Цитата
Внимание: Цикл foreach оперирует не исходным массивом, а его копией.


Спустя 12 минут, 28 секунд (23.09.2011 - 23:53) neadekvat написал(а):
Цитата (redreem @ 23.09.2011 - 12:40)
ну и сей казус объяснить кроме как тем, что это очередной ляп в php-реализациях - я ничем не могу.

Ой, и правда.
А давайте на четвертой версии php попробуем?

Мало ли чего там в php 5.1 и 5.2 было? Там на каждую новую версию (5.x.y - я про y) столько багфиксов выдают, что порой волосы шевеляться. А ты от старых версий что-то хочешь.

В php 5.3 все ок.

Спустя 3 минуты, 59 секунд (23.09.2011 - 23:57) kirik написал(а):
redreem
Вот за это я и не люблю всякие там php.su.
Цитата (http://www.php.su/learnphp/cs/?cycles#foreach)
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.


По поводу утверждения - он работает с самим массивом (оригинальным), пока ты не внёс изменения в массив (т.е. php создаёт копию только в крайнем случае).

Спустя 24 минуты, 6 секунд (24.09.2011 - 00:21) redreem написал(а):
хорошо, тогда последний вопрос: почему различие в работе на локальном хосте и на внешнем???

Спустя 56 минут, 49 секунд (24.09.2011 - 01:18) kirik написал(а):
redreem
Не могу знать.. может у тебя локально денвер стоит, а он, как известно, по-своему работает smile.gif

Спустя 9 часов, 12 минут, 17 секунд (24.09.2011 - 10:30) redreem написал(а):
kirik, vertrigo
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.