Несколько циклов 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 - причины использовать итераторы?,