Несколько циклов foreach и просто еще одна история утечки памяти

Кому может касаться,

Как мы уже знаем foreach это болезненная и головная боль, в то время как мы используем ее, чтобы справиться с облаками или миллионами записей. И это станет кровавым убийцей машины, если у нас есть близнец или может быть больше foreach в ряд:)

Например,

foreach ($parent as $parentData) {
    // few conditional added here
    $parentObj = $this->extract();
    foreach ($chilren as $childrenData) {
        if ($childrenData['id'] === $parentData['id']) {
            $childrenObj = $this->extract();
            $parentObj->setData($childrenObj);
            // and even more evil things come here....
        }
    }
    $parentObj->save();
}

В моей ситуации у меня есть близнец foreach, И каждый из них содержит около 50000 ~ 70000 записей. $parent а также $children параметры передаются в метод.

Источник необработанных данных как $parent а также $children являются CSV-файлами А я пользуюсь yield чтобы превратить их в foreach,

Там нет проблем с yield, поверь мне. Это гарантировано 60k+ игроком этого сайта:)

Если вы беспокоитесь о коде: /questions/8870536/php-pamyat-ischerpana-pri-ispolzovanii-arraycombine-v-tsikle-foreach/8870558#8870558

Возвращаясь к своему беспокойству, я пытался unset оба $parentObj а также $childrenObj в конце первого foreach, но, к сожалению, это не работает. Я также пытался использовать ссылки &$parentData, но результат тот же.

Как я мог сделать эту работу до конца моей жизни?

Заранее спасибо.

ОБНОВЛЕНО

В этом случае мне мало кто посоветовал использовать итераторы SPL. Может кто-нибудь объяснить, пожалуйста, как это работает?

Благодарю.

ОБНОВЛЕНО № 2

Я использую SPL Iterator, ниже приведен новый код:

$parent = new IteratorIterator(new ArrayIterator($parentArr));
$children = new IteratorIterator(new ArrayIterator($chilrenArr));
foreach ($parent as $index => $parentData) {
    $parentObj = null;
    // few conditional added here
    $parentObj = $this->extract();
    $childrenObj = null;
    foreach ($chilren as $key => $childrenData) {
        if ($childrenData['id'] === $parentData['id']) {
            $childrenObj = $this->extract();
            $parentObj->setData($childrenObj);
            // and even more evil things come here....
        }
    }
    $parentObj->save();
    $childrenObj->save();
}

3 ответа

Наверное, $parentObj = $this->extract(); не использует ссылку и $parentObj->setData($childrenObj); заставляет PHP создавать копию из исходного массива для каждого изменяемого элемента.

Другой подход заключается в перемещении указателя в while цикл:

reset($array);
while (list($key, $val) = each($array)) {
    $array[$key] = ++$val;
    echo "$array[$key]\n";
}

Чтобы использовать итератор SPL:

// create a new ArrayIterator and pass in the array
$parentDataIter = new ArrayIterator($parentData);

// loop through the object one item at a time memory-wise
foreach ($parentDataIter as $key => $value) {
    // ...
}

Итераторы SPL - это не единое целое, а просто общее название для них (итераторы стандартной библиотеки PHP). Доступные из них работают совершенно по-другому, но следующий поток переполнения стека уже попытался объяснить их использование и преимущества / недостатки довольно хорошо. PHP - причины использовать итераторы?,

Другие вопросы по тегам