4

There are numerous questions out there about the safety implications of manipulating an array when using foreach on it. I can't find any questions on doing this in a while loop, though.

So I wonder, is it safe to do this? Below is an example script in PHP and I'm not sure if this is alright.

while ($item = array_pop($array)) {
  findMoreItems($item, $array);
}

function findMoreItems($item, &$array) {
  // Returns null if no more items are found
  $newItem = someFuncFromServer($item);

  if ($newItem) {
    array_push($array, $newItem);
  }
}

By safe I mean: can I be sure that no items are skipped in the loop?

Bram Vanroy
  • 27,032
  • 24
  • 137
  • 239
  • 8
    As safe as an infinite loop can be. – apokryfos Oct 28 '16 at 14:01
  • 3
    This question is, surprisingly, a lot more in depth than it looks. I could explain it, but I'll probably not explain it good enough. See [here](https://nikic.github.io/2011/11/11/PHP-Internals-When-does-foreach-copy.html) for starters, [here](http://stackoverflow.com/questions/3307409/php-pass-by-reference-in-foreach) and [here](https://www.toptal.com/php/10-most-common-mistakes-php-programmers-make). It's not complicated, but it's just tricky to explain properly. And @apokryfos that's not an infinite loop. – Andrei Oct 28 '16 at 14:04
  • it is a "potential" infinite loop. – mister martin Oct 28 '16 at 14:06
  • I edited in the obvious, so no: there is no infinite loop considering the data I'm working with. – Bram Vanroy Oct 28 '16 at 14:06
  • Use `$array[] = $newItem;` it's faster than array_push – mcklayin Oct 28 '16 at 14:07
  • The `if` wasn't there when I commented that. @Andrew this is a while loop. A foreach is a completely different story. – apokryfos Oct 28 '16 at 14:07
  • Absolutely, 2 different matters, no doubt about it. OP was asking(from what I can understand) the implications of using `foreach` as opposed to `while` since it's already clarified that `while` has none of the pitfalls of `foreach` which is a specific language construct in php. – Andrei Oct 28 '16 at 14:10
  • @Andrew I'm actually asking a while loop, and *not* about the foreach loop. – Bram Vanroy Oct 28 '16 at 14:11
  • 1) What do you mean by 'safe'? 2) Is someFuncFromServer a remote call? You may run into timeouts then really easy :-) – Blackbam Oct 28 '16 at 14:11
  • @BramVanroy I stand corrected then. For the record, I see nothing wrong with your code. – Andrei Oct 28 '16 at 14:12
  • The array is always shrinking or staying constant size - therefore it will always terminate if you make sure that at some time there is no more $newItem. – Blackbam Oct 28 '16 at 14:14

1 Answers1

1

Your code is essentially equivalent to :

$item = array_pop($array);
while ($item) {
  findMoreItems($item, $array);
  $item = array_pop($array)
}

function findMoreItems($item, &$array) {
  // Returns null if no more items are found
  $newItem = someFuncFromServer($item);

  if ($newItem) {
    array_push($array, $newItem);
  }
}

Now if you rewrite this in the above way it is obvious that the code will not do anything like copy references or array points or anything like that which is what foreach does. foreach does that because it relies on the internal array pointer which array_pop and array_push do not.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • After all I can not think of a way how this could go wrong after all. Your answer regarding foreach is true. Rationally it is totally safe. However it would be interesting to drive some real life tests with a whole lot of data to see if an error may happen - just to be sure if PHP does not behave unexpectedly. – Blackbam Oct 28 '16 at 14:28
  • I think the much bigger risk is that any bug in `someFuncFromServer` may cause this to become an infinite loop. – apokryfos Oct 28 '16 at 14:48