Rantaroni

An Infinite L… Oops, I’m on Vacation

Published

It was June 2013. I’d just started in a new role where I was writing PHP (and using jQuery Mobile 😳). I’d written PHP before, this but this was my first time writing it in a professional context. It was also my first time navigating a PHP codebase that I hadn’t written entirely on my own.

I was working on a change—the specifics of which elude me—that required adding a for loop. It probably looked something like this:

for ($i = 0; $i < $something; $i++) {
  // do something
}

I committed my change and went on vacation. When I returned, I learned that there’d been some excitement in my absence. Apparently, my change was triggering an infinite loop. Oops!

My for loop was nested inside another for loop, and both of those loops used $i as their loop counter.

Reusing a loop counter in PHP leads to some strange behaviors:

  • If $something matches the outer loop’s $i, the code is correct. The inner loop mutates $i, does its work, and then puts back the value of $i that’s expected by the outer loop.

  • If $something is larger than the outer loop’s $i, the outer loop will skip some of its iterations. That’s incorrect behavior! An even stranger corollary: if the outer loop happens to be on its last iteration, the behavior is correct because the “skipped” outer loop iterations don’t exist!

  • If $something is smaller than the outer loop’s $i, the outer loop will repeat some of its iterations. That’s incorrect behavior, and it could produce an infinite loop! (The loop might terminate for some other reason, but it’ll definitely run more times than expected!)

Looking back now, I have some takeaways:

  • Always look at the containing scope (especially if it’s large).

  • Decompose large functions into smaller pieces (especially if they’re large).

  • Pick a language that forces variables to be explicitly declared. (General advice: don’t ever pick PHP. 😏)

  • Use for-in loops that don’t require any loop counter.

  • And, perhaps most importantly: don’t commit (bugs) before going on vacation.