PHP for Loop

Chapter 24 30 mins

Learning outcomes:

  1. Introduction to loops
  2. What is the for loop meant for
  3. Syntax of for
  4. Basic for loop examples
  5. Nested for loops
  6. The break and continue keywords
  7. The return keyword

Introduction

Loops, also known as loop statements or iteration statements, are amongst those ideas in programming without which it's not just difficult but totally impossible to imagine this modern era of computing. Computers are the heart of automation and loops are the forerunner in enabling that.

Essentially a loop is merely a block of code together with some set of instructions on how long to keep that code running again and again. Back in the day when programming languages were invented, we didn't have the loops that we have today.

Over time as programming matured, people realized the need of such a neat programming construct that could fit in well with our intuitive reasoning of repetition. And thus came in the idea of loops as we use them today.

The two most conventional looping statements provided by almost all mainstream languages are for and while. Each has its own specific purpose but the idea is the same — keep repeating code until some condition becomes false.

In this chapter, we start off by exploring all the nitty gritty details of the for loop, followed by those of while in the next chapter.

Let's begin.

What is for meant for?

So what is for meant for?

Well, precisely speaking:

The for loop is meant to repeatedly execute a piece of code a known number of times.

For instance, if we want to print 'Hello' a thousand times, or process as many <a> elements in the HTML document as given by the variable anchorsLength, then what we need is the for loop.

In both of these cases, we know the limit to the iteration in one way or the other.

Compare this with, let's say, repeatedly asking the user to input a number until the input is -1. Here clearly we don't know how many times would the code repeat before execution jumps out of it, hence this is not a situation meant for for (however, technically, it could be used here as well — we'll shortly see how).

To restate it, for is used to iterate a known number of times.

This is the reason why it's common to use for to iterate over arrays using their length property or, in general, over any other sequence.

Anyways, with the purpose of for understood, it's time to see how to write a basic for loop.

Syntax of for

The for statement begins with the for keyword, followed by a set of configurations enclosed in a pair of parentheses (()), known as the loop's header, followed by the statement to repeatedly execute, known as the loop's body.

Here's the syntax:

<?php

for (initialization; condition; update)
   statement;

The pair of parentheses following the for keyword consists of three different configurations, each separated by a semicolon (;).

  1. $initialization — here any variables to be used in the loop are initialized to given values.
  2. condition — the condition that's evaluated before every iteration. If it evaluates to true, the loop's body is executed, or else execution moves out of the loop.
  3. update — an expression that's evaluated after every iteration. Typically this updates a variable's value that's used in the loop's condition so that it eventually becomes false at a certain point, and thus the loop comes to an end.

Note that only expressions are allowed in each of these three sections.

Moreover, it's invalid to include more or less than two semicolons in the for loop's header. The individual expressions can be omitted but the semicolons have to be there.

We'll see numerous examples of for loops shortly below to help us understand all this discussion.

Now, if we were to go with all this description of the syntax of for, we'd arrive at the following syntax.

<?php

for ([initialization]; [condition]; [update])
   statement;

Notice the [ ] around each of the three configuration expressions — they signify the fact that all the three expressions are optional.

Simple examples

In this section, we aim to see a couple of examples of the usage of for. With each example, we cover a lot of aspects of how to rewrite the for loop.

Basic counting

Consider the problem of echoing 0 to 4 using a for loop.

This could very easily be done as follows:

<?php

for ($i = 0; $i < 5; $i++) {
   echo $i, "\n";
}
0 1 2 3 4

Let's understand how this loop works:

  1. First, in the statement $i = 0, we define a new variable $i, set to 0. This variable will keep track of the iteration we are currently on, and obviously also be used in the output. Such a variable that's meant to drive a given loop is often known as a loop variable, or even as a loop counter.
  2. Secondly, the condition $i < 5 means that $i should be less than 5 for the given body to be executed.
  3. Lastly, the update expression $i++ means that after every iteration, $i is incremented by 1.

Hence, when $i = 0 (initially), the loop executes; when $i = 1, the loop executes; when $i = 2 the loop executes; this goes on until $i becomes equal to 5 at which point the evaluation of $i < 5 yields false and consequently the loop ends.

Simple, isn't this?

Note that the same output could've also been obtained by slightly modifying the condition. That is, instead of using $i < 5, we could've also used $i <= 4. This is because the condition $i <= 4 (akin to $i < 5) yields true for all the values 0, 1, 2, 3 and 4.

Here's an illustration of this fact:

<?php

for ($i = 0; $i <= 4; $i++) {
   echo $i, "\n";
}
0 1 2 3 4

Iterating over an array

One of the most common uses of for is to iterate over an array, or any other sequence, such as a string.

The main thing used in this case is the length of the sequence (i.e. the total number of elements in it). For arrays, we already know that the length is obtained via the count() function.

Likewise, what we do is start at the index 0 and go as long as the index remains less than the length of the sequence. That's because the last element's index is one less than the length of the sequence, and therefore we don't have to end right at that very point.

Let's consider an example. In the code below, we have an array of numbers:

<?php

$nums = [1, 10, 5, -9, -1];

What we want to do is to output each number separately. This is accomplished as follows:

<?php

$nums = [1, 10, 5, -9, -1];

for ($i = 0; $i < count($nums); $i++) {
   echo $nums[$i], "\n";
}
1 10 5 -9 -1

Once again, the loop's counter $i begins at 0 and goes right up to count($nums) (obviously excluding it), being incremented after each iteration. Inside the loop's body, the $ith element of $nums is echoed using $nums[$i].

Simply amazing!

If we want to, we can add a bit of spice in the code above. Instead of merely echoing the current item of the array, we can also label it, and thus specify which index does the item have.

Consider the code below:

<?php

$nums = [1, 10, 5, -9, -1];

for ($i = 0; $i < count($nums); $i++) {
   echo 'nums[' . $i . ']: ' . $nums[$i], "\n";
}
nums[0]: 1 nums[1]: 10 nums[2]: 5 nums[3]: -9 nums[4]: -1

As can be seen, this time the output is a bit more detailed, showcasing the index of each echoed item.

Alright, it's now time for one very quick and easy task...

Given the same $nums array as shown above, write some code to output its elements in reverse-order using a for loop.

The expected output is the following:

-1 -9 5 10 1

To go in reverse order, we ought to begin at the very last index, proceed backwards, and continue as long as the index remains greater than or equal to 0.

Hence, we get to the following code:

<?php

$nums = [1, 10, 5, -9, -1];

for ($i = count($nums) - 1; $i >= 0; $i--) {
   echo $nums[$i], "\n";
}

Moving on, one common thing you'll notice across code snippets out there is depicted as follows:

<?php

$nums = [1, 10, 5, -9, -1];

for ($i = 0, $len = count($nums); $i < $len; $i++) {
   echo 'nums[' . $i . ']: ' . $nums[$i], "\n";
}

Can you spot the difference? Well, it's the expression $len = count($nums) and then the condition's modification to $i < $len from $i < count($nums).

So what's so special about this change?

Recall that the loop's condition, i.e. the second segment in the loop's header, is evaluated before every iteration. When the condition is $i < count($nums), the count() function is called again and again and again in this evaluation.

To prevent this overhead of a function call, programmers typically cache (temporarily store) the length of the sequence in a variable and then use this variable instead.

In the code above, the $len variable acts as a cache for the length of $nums. Once stored in it, we can easily retrieve the array's length without having to reinvoke count($nums).

Getting numbers input

Suppose we want to obtain some numbers and then add them together. How many numbers we want to add is specified in an initial prompt input. Thereafter, as many additional prompts are made, asking for each of the numbers to be added.

The code below accomplishes this:

<?php

echo 'How many numbers?> ';
$n = (int) fgets(STDIN);

$sum = 0;
for ($i = 0; $i < $n; $i++) {
   echo 'Enter number ', $i + 1, '> ';
   $sum += (int) fgets(STDIN);
}

echo $sum;
How many numbers?> 3 Enter number 1> 50 Enter number 2> 40 Enter number 3> 1 91

Notice that we begin the loop at $i = 0 even though we could've begun at $i = 1 and obviously changed $i < $n to $i <= $n likewise.

The thing is that it's very conventional and natural to begin at 0 and iterate the given number of times using the < operator, even though sometimes the 0 might not have any practical significance, just like in the code above.

Note that if the expression $i + 1 was repeatedly needed in the loop's body above, then we might've considered changing $i = 0 (in the loop's header) to $i = 1 and then obviously the conditional expression $i < $n to $i <= $n as well to ultimately replace $i + 1 with $i.

However, the expression $i + 1 was used only once in the code above and likewise we didn't consider modifying the loop's header.

Nested loops

A for loop's body is a piece of code just like any other piece of code in a program. This means that it could contain another for loop as well.

We usually refer to this as a nested loop. The inner loop is said to be nested inside the outer loop.

Nested loops are extremely common in programming. The majority of algorithms and data structures that you'll implement in your programming career will require you to employ nested loops. So let's quickly see how to set up a nested for loop.

First let's come up with a scenario. Suppose we have to print ordered pairs of the form (i, j) where i is 0, 1, 2 and $j is 0, 1, 2.

The way we'd do so is to first set $i = 0 in the outerloop and then iterate with $j set to 0, 1 and 2; then increment $i and repeat the iteration over $j; then increment $i again and repeat the iteration over $j.

Here's the code:

<?php

for ($i = 0; $i < 3; $i++) {
   for ($j = 0; $j < 3; $j++) {
      echo "($i, $j)\n";
   }
}
(0, 0) (0, 1) (0, 2) (1, 0) (1, 1) (1, 2) (2, 0) (2, 1) (2, 2)

It's very intuitive to follow along. For each iteration of the outer loop, the inner loop iterates three times.

Conventional naming: $i, $j and $k

Note that using $i and $j as the loop counter variables in a nested loop is a convention. In fact, when there are a total of three loops, the variables used are $i, $j and $k in that order, starting with the outermost loop.

Perhaps this has been influenced from the theory of vectors and matrices in mathematics, where the same names are used to denote given variables.

Whenever designing nested loops in this course, we'll follow this convention unless there is a valid reason to use some other naming.

Time to test you understanding of nested loops.

Write some code to achieve the following output:

(0, 0) (1, 0) (2, 0) (0, 1) (1, 1) (2, 1) (0, 2) (1, 2) (2, 2)

Before writing the code, we have to focus on the output and see which element in the ordered pairs is changing quicker than the other one. That's clearly the first element.

Hence, this hints us that the inner loop (with $j as its counter variable) will produce this first element of the ordered pair. The second element will be produced by the outer loop (with $i as its counter variable).

Here's one way to accomplish this task, and the preferrable way:

<?php

for ($i = 0; $i < 3; $i++) {
   for ($j = 0; $j < 3; $j++) {
      echo "($j, $i)\n";
   }
}

Another way could simply be to swap the variable names $i and $j:

<?php

for ($j = 0; $j < 3; $j++) {
   for ($i = 0; $i < 3; $i++) {
      echo "($i, $j)\n";
   }
}

This isn't preferred since the variable $j comes first in the outer loop followed by $i in the inner loop — ideally it should be the case that $i comes first and then $j.

The break and continue keywords

JavaScript, like almost all mainstream languages, provides two common control flow commands that dictate the execution of a loop — break and continue.

break

As the name suggests,

break serves to break execution out of the loop that it is placed within

It's more or less like a shortcut to terminate a given loop. Anything following the break command isn't executed in the loop — execution immediately jumps out.

Let's see a quick example.

In the code below, we have a basic loop, counting from 0 to 5. The if conditional inside the loop checks for $i === 2. The moment that happens, execution jumps out of the loop:

<?php

for ($i = 0; $i < 5; $i++) {
   if ($i === 2) {
      break;
   }

   echo $i, "\n";
}

Here's the output produced by this code:

0 1

As is evident, the echo $i statement executes just twice. In the third iteration, when $i === 2 is true, leading to break executing (on line 5), the echo $i statement (on line 8) gets ignored.

Let's try to modify the position where break is called:

<?php

for ($i = 0; $i < 5; $i++) {
   echo $i, "\n";

   if ($i === 2) {
      break;
   }
}

Here's the output produced by this code:

0 1 2

This time, since echo $i is before the break command, it executes for the third iteration as well (when $i = 2), unlike previously, and hence we get the third output.

break only breaks execution out of the loop where it is used — it won't break execution out of the parent loop (if there's any).

break is undoubtedly a useful command, but use it very carefully. It does reduce the readability of code. Whenever possible, try to avoid using break in place of a simple and intuitive conditional expression in the header of the loop.

Let's see an instance of what does it actually mean for break to reduce the readability of code.

Consider the following code:

<?php

$nums = [1, 11, 3, 2, 5];

for ($i = 0; $i < count($nums); $i++) {
   if ($nums[$i] % 2 === 0) {
      break;
   }

   echo $nums[$i], "\n";
}
1 11 3

The loop's header clearly shows that we want to iterate over the entire array. However, inside the loop, the additional if conditional checks whether the current element is an even number. If it is, the loops exits.

In other words, we want to process the elements of the array until an even number is encountered.

As you may agree, this isn't immediately evident just by reading the loop's header. Ideally, we should try to be as informative as we can in laying out the loop's condition in order to make sure that anyone reading the code can pick up the purpose of the loop right away.

A much better approach would be to join both the given conditions together, as done below:

<?php

$nums = [1, 11, 3, 2, 5];

for ($i = 0; $i < count($nums) && $nums[$i] % 2 !== 0; $i++) {
   echo $nums[$i], "\n";
}

The loop's condition simply means that the execution of the loop should continue if $i is less than count($nums) (i.e. we don't exceed the last element of the array) and if $nums[$i] is not an even number (i.e. we don't want to process an even number).

See how break has been removed from our code, yet the loop still works as it did before.

The point of this example is to emphasize on the fact that break should be used sparingly in loops. This isn't because it degrades performance — it doesn't affect the performance of the script in any way. It's only because it costs the fluid readability of the given code.

That's it.

continue

Let's now move to continue.

The continue keyword serves to signal to the JavaScript to the engine to skip the current iteration and move to the next one.

Effectively this means that any code following the command isn't executed, and execution moves to the next iteration if there is any remaining. If no iteration is remaining, then obviously the loop terminates.

Let's consider a quick example.

In the code below, we iterate over the given array $nums and skip the loop's body if the current element is an even number:

<?php

$nums = [1, 11, 3, 2, 5];

for ($i = 0; $i < count($nums); $i++) {
   if ($nums[$i] % 2 === 0) {
      continue;
   }

   echo $nums[$i], "\n";
}
1 11 3 5

Clearly, this code could be improved by removing the call to continue and instead using an if conditional to check if a log ought to be made (i.e. the current number is odd).

This is accomplished as follows:

<?php

$nums = [1, 11, 3, 2, 5];

for ($i = 0; $i < count($nums); $i++) {
   if ($nums[$i] % 2 !== 0) {
      echo $nums[$i], "\n";
   }
}
1 11 3 5

Without any doubt, this second code snippet is much more readable than the previous one that employed continue.

Long story short: continue, as with break, is a very useful command to control the execution of a given loop. However, we should make sure to use it sparingly as well, just like break, and rather try to use if...else conditionals in a way that gets the same job done but in a more readable manner.

With this done, it's time to see the return keyword as used inside a loop.

The return keyword

As we saw in the chapter PHP Functions, the return keyword is used inside a function to immediately terminate execution and return a given value to the calling context.

We also know that it's invalid to use return outside a function. Therefore, if we want to use return inside a loop, the loop has to be part of a function's body.

Using return in a loop, which is obviously itself a part of function, is a very common idea. Why?

Simply because it does two things:

  1. It breaks execution out of the function which effectively means that no matter how many loops are nested together, return would exit them all and the containing function as well.
  2. It returns a value to the calling context, i.e. the place where the function was called.

One quick example could be a function that searches for a given number in a matrix (represented as an array of arrays).

The search would use a double nested loop and, inside the inner loop, a mere conditional to check for the number. If it finds the number we were searching for, true is immediately returned before bringing the entire execution of the function to a halt.

Following is this example brought to the glyphs of code:

<?php

$matrix = [
   [0, 5, 6],
   [1, 2, 10],
   [0, 0, -1],
];

function search_matrix($matrix, $value) {
   for ($i = 0, $n = count($matrix); $i < $n; $i++) {
      for ($j = 0; $j < $n; $j++) {
         if ($matrix[$i][$j] === $value) {
            return true;
         }
      }
   }
   return false;
}

var_dump(search_matrix($matrix, 10));
var_dump(search_matrix($matrix, 2));
var_dump(search_matrix($matrix, -50));
bool(true) bool(true) bool(false)

Had this example been implemented without using return, we would've had to make a lot of changes, and then the code won't remain as simple as it looks right now.

And this is it.