2

To whom may concern,

As we are already known foreach is a painful and a headache while we using it to deal with thoudsands or millions of record. And it will become a bloody killer machine if we have a twin or may be more foreach in a row :)

For example,

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();
}

In my situation, I have twin foreach. And each one contains approximate 50,000 ~ 70,000 records. $parent and $children are parameters passed to the method.

The raw data source both of $parent and $children are CSV files. And I'm using yield to transform them to be travelsable with foreach.

There is no trouble with yield, belive me. It's guaranteed by a 60k+ player of this site :)

If you concern about the code: https://stackoverflow.com/a/37342184/2932590

Back to my concernation, I tried to unset both of $parentObj and $childrenObj at the end of first foreach, but unfortunately it's not working. I also tried to using the references &$parentData, but the result is same.

How could I make this work till the rest of my life?

Thanks in Advanced.

UPDATED

I got few advised to use SPL Iterators in this case. Can anyone please explain me how it work also?

Thanks.

UPDATED #2

I'm using SPL Iterator, below is the new code:

$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();
}
Community
  • 1
  • 1
Toan Nguyen
  • 901
  • 13
  • 35

3 Answers3

0

To use SPL iterator:

// 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) {
    // ...
}
j4hangir
  • 1,760
  • 1
  • 10
  • 13
0

SPL iterators are not a uniform thing but just the collective name for them (Standard PHP Library iterators). The ones available works quite differently but the following stack-overflow thread has already tried to explain their uses and pros/cons quite well. PHP - Reasons to use Iterators?.

Community
  • 1
  • 1
Björn Fyrvall
  • 231
  • 1
  • 7
  • I need to reduce my memory usage. That is why I choose Iterators, and yes I read that question before create this one. – Toan Nguyen Jun 03 '16 at 10:20
0

probably, $parentObj = $this->extract(); doesn't use a reference and $parentObj->setData($childrenObj); makes PHP to create a copy from initial array for each element that is changed.

another approach is to move the pointer in a while loop:

reset($array);
while (list($key, $val) = each($array)) {
    $array[$key] = ++$val;
    echo "$array[$key]\n";
}
altcatalin
  • 11
  • 3
  • based on the information you provided it seems like there is a problem with the way you update an array - [explanation](http://stackoverflow.com/a/14854568/1539119). for a better response, we need a more details about these methods $this->extract(), $parentObj->setData($childrenObj), `code`$parentObj->save()`code` at least in pseudocode – altcatalin Jun 07 '16 at 20:50