Tools Blog Learn Quizzes Smile API Log In / Sign Up
Tools Blog Learn Quizzes Smile API Log In / Sign Up
« Return to the tutorials listFeatured in PHP Weekly
We have updated our privacy policy to let you know that we use cookies to personalise content and ads. We also use cookies to analyse our traffic and we share information about your use of our site and application with our advertising and analytics partners. By using this website or our application you agree to our use of cookies. Learn more about the way this website uses cookies or remove this message.

3 PHP loops gotchas

December 19, 2014 Difficulty: 20 / 50 Tweet
Froot-loops

This post is to give you a few tips that you should remember when dealing with loops in PHP. You will learn why it is bad practice to initialize variables inside a loop, why a do-while can cause headaches if one doesn't understand it properly, when for loops should replace foreach and some more interesting loop gotchas.

Do your best not to initialize variables or call functions inside loops

If a variable will only have one value, there's no reason why you should initialize it with each iteration.

Here's a wrong way of doing this:

  
    <?php
    $price   = 10;
    $taxes   = 0.1;
    $months  = array('January', 'February', 'March');
    foreach ($months as $month) {
      $price_with_tax = $price + ($price*$taxes);
      echo '<p>' . $month . '-> $' . number_format($price_with_tax, 2) . '</p>';
    }
    ?>
  

Instead of calculating the $price_with_tax for every iteration, because it will alway remain the same, why not move the calculation and the function call above the loop so it doesn't get executed every time.

  
    <?php
    $price   = 10;
    $taxes   = 0.1;
    $price_with_tax = number_format($price + ($price*$taxes), 2);

    $months  = array('January', 'February', 'March');
    foreach ($months as $month) {
      echo '<p>' . $month . '-> $' . $price_with_tax . '</p>';
    }
    ?>
  

Another example of bad code that executes an expensive operation with every iteration is when counting the elements of a collection in the conditional part of a loop.

  
    <?php
    // This example will count the number of elements in the array with each iteration
    $months  = array('January', 'February', 'March');
    for ($i = 0; $i < count($months); $i++)
    {
      echo $months[$i];
    }
    // A better way of doing this is:
    $months = array('January', 'February', 'March');
    $length = count($months);
    for ($i = 0; $i < $length; $i++)
    {
      echo $months[$i];
    }
    ?>
  

Do-while loops will always execute at least once

A normal while loop will check if a condition evaluates to true before executing the first time. On the other hand, do-while loops will execute the iteration and then check if the condition inside the while statement is true. This can cause a lot of problems if you assume that the condition is checked before entering the loop.

In the first example, even if $i is not 1, the number 0 is printed on the screen because the block of code inside do{ //code } is executed once before checking the condition. However, in the second example the script first checks if $i is 1.

  
    <?php
    $i=0;
    do {
      echo $i . PHP_EOL; //prints 0
    } while ($i==1);

    $i=0;
    while ($i==1)
    {
      echo $i . PHP_EOL; //doesn't execute
    }
    ?>
  

Choose the loop that makes sense depending on the context

If you are looping through a collection element, like an array, there's no good reason not to use foreach. In such cases, using for is harder to read and it doesn't bring any real performance benefits. Also foreach can iterate through associative arrays and objects and you can't achieve that with for loops. However, for is great for integer based iterations especially when you need to know the last value of the iteration counter or you need to play with values from previous or future iterations. Also, for loops can also be used for looping through the letters of the alphabet. Here's a cool example that can be used when taking values from an excel file (columns 'A' to 'AZ' for each of the first 10 rows).

  
    <?php
    for ($row=1; $row <=10 ; $row++)
    { 
      for($col = 'A'; $col != 'BA'; $col++)
      {
          echo $row . $col . ' ';
          if($col=='AZ')
            echo PHP_EOL; // end one row
      }
    }
    ?>
  

When dealing with nested loops, break allows you to exit them all at once

You all know that break exits a loop and continue is used to jump straight to the next iteration. However, break accepts an optional numeric argument that represents the number of nested loops the script should exit at once. In the example below, the script will only print '1A' instead of '1A2A3A4A5A6A7A8A9A10A' because it will break out of both for loops.

  
    <?php
    for ($row=1; $row <=10 ; $row++)
    { 
      for($col='A'; $col !='K' ; $col++)
      {
          if($col=='B')
            break 2;
          echo $row . $col;
      }
    }
    ?>
  
comments powered by Disqus

Better Docs For A Better Web - Mozilla Developer Network

Alerts

2017-09-21 - The SoapClient implementation in PHP before 5.4.40, 5.5.x before 5.5.24, and 5.6.x before 5.6.8 allows remote attackers to cause a denial of service (application crash) or possibly execute arbitrary code via an unexpected data type, related to "type confusion" issues in the (1) SoapClient::__getLastRequest, (2) SoapClient::__getLastResponse, (3) SoapClient::__getLastRequestHeaders, (4) SoapClient::__getLastResponseHeaders, (5) SoapClient::__getCookies, and (6) SoapClient::__setCookie methods. Read more ...
2017-09-21 - The exception::getTraceAsString function in Zend/zend_exceptions.c in PHP before 5.4.40, 5.5.x before 5.5.24, and 5.6.x before 5.6.8 allows remote attackers to execute arbitrary code via an unexpected data type, related to a "type confusion" issue. Read more ...

See All Entries...