Почему не хватает памяти в самом простом цикле и с массивом из 3-х элементов?

Есть функция, которая выводит категории начиная с самого верха:

function getFullCategoryName($strCategoryId, $arrCategories)
{
    $strCategoryIdPaent = NULL;
    $arrCategoryCurr = isset($arrCategories[$strCategoryId]) ? $arrCategories[$strCategoryId] : NULL;
    $arrCategoriesNames = [];
    while (is_array($arrCategoryCurr)) {
        $arrCategoriesNames[] = $arrCategoryCurr['title'];
        if ($arrCategoryCurr['parentId'] && isset($arrCategories[$arrCategoryCurr['parentId']])) {
            $arrCategoryCurr = $arrCategories[$arrCategoryCurr['parentId']];
        } else {
            $arrCategoryCurr = NULL;
        }
    }
    krsort($arrCategoriesNames);
    return implode(' > ', $arrCategoriesNames);
}

Всего с 3 элементами массива я получаю сообщение об ошибке:

"Разрешенный размер памяти 134217728 байт исчерпан"

Я понимаю, что использую что-то не так. Пожалуйста, помогите мне понять, что именно.

Это мой входной массив:

$arrCategories = array (
    193450 => 
    array (
        'id' => '193450',
        'parentId' => '193450',
        'title' => 'Blood glucose meter',
    ),
    193451 => 
    array (
        'id' => '193451',
        'parentId' => '193450',
        'title' => 'Sugar test strips',
    ),
    193452 => 
    array (
        'id' => '193452',
        'parentId' => '193452',
        'title' => 'Blood glucose meter',
    ),
);

Это вызов функции:

$strCategoryId = 193450;
getFullCategoryName($strCategoryId, $arrCategories);

person oshka    schedule 20.05.2019    source источник
comment
else { $arrCategoryCurr = NULL; } эта часть не срабатывает   -  person Shobi    schedule 20.05.2019
comment
Может быть. Но когда я изменил NULL на строку NULL phpfiddle.org/main/code/9h6v-wu42 ошибка та же самая E_ERROR: тип 1 -- Допустимый размер памяти 134217728 байт исчерпан (попытка выделить 134217736 байт) -- в строке 29   -  person oshka    schedule 20.05.2019
comment
Изменение NULL на строку не проблема. Условие else никогда не выполняется, поэтому $arrCategoryCurr никогда не устанавливается в NULL (или 'NULL', или что-то еще), поэтому is_array($arrCategoryCurr) бесконечно остается истинным, поэтому цикл никогда не заканчивается.   -  person deceze♦    schedule 20.05.2019


Ответы (2)


У ваших (примерных) данных есть проблема, основанная на моем прочтении вашей функции.

parentId и index в некоторых элементах совпадают. Это создало бы бесконечный цикл, основанный на том, что я могу понять из вопроса.

Лучшей структурой было бы что-то вроде следующего, с некоторой проверкой ошибок в цикле:

function getFullCategoryName($strCategoryId, $arrCategories) {
    // set a base / default value
    $arrCategoriesNames = [];
    // do we even have anything to work with?
    if (isset($arrCategories[$strCategoryId])) {
        // at least one entry
        do {
            // get the title
            $arrCategoriesNames[] = $arrCategories[$strCategoryId]['title'];

            // get the next id and error check the data
            if ((isset($arrCategories[$strCategoryId]['parentId'])) && 
                ($strCategoryId != $arrCategories[$strCategoryId]['parentId'])) {
                // next index found and not the same
                $strCategoryId = $arrCategories[$strCategoryId]['parentId'];

            } else {
                // either no parentId or a parentId that matches the current 
                // index. If that is the case, go no further.
                $strCategoryId = false;
            }
            // you could add another error check if you like.
            // if (count($arrCategoriesNames) == count($arrCategories)) {
            //     // go no further as data has a loop
            //     $strCategoryId = false;
            // }
        } while($strCategoryId);

        // sort the data? why?
        krsort($arrCategoriesNames);
    }
    // return a string
    return implode(' > ', $arrCategoriesNames);
}

И тестирование массива образцов;

$result = getFullCategoryName(193450,$arrCategories);
var_dump($result);

Возвращает следующее:

string(19) "Blood glucose meter"
person Tigger    schedule 20.05.2019

Цикл while (is_array($arrCategoryCurr)) никогда не заканчивается, так как блок else цикла $arrCategoryCurr = NULL; никогда не вызывается.

Это происходит потому, что у вас есть цикл, в котором идентификатор узла совпадает с его родительским идентификатором. Посмотрите на свой массив:

....
'id' => '193450',
'parentId' => '193450',
...

Чтобы исправить это, измените оператор if на:

if ($arrCategoryCurr['parentId'] && $arrCategoryCurr['parentId'] != $arrCategoryCurr['id'] && isset($arrCategories[$arrCategoryCurr['parentId']])) {
person dWinder    schedule 20.05.2019
comment
Спасибо @dWinder! Я изменил свой код так же, как вы написали! - person oshka; 20.05.2019