Saving State Between Function Calls with the 'static' Statement

Variables within functions have a short but happy life on the whole. They come into being when the function is called and die when execution is finished. Once again, this is as it should be. It is usually best to build a script as a series of self-contained blocks, each with as little knowledge of others as possible. Occasionally, however, you may want to give a function a rudimentary memory.

Let's assume that we want a function to keep track of the number of times it has been called. Why? In our examples, the function is designed to create numbered headings in a script that dynamically builds online documentation.

We could, of course, use the global statement to do this. We have a crack at this in Listing 6.9.

Listing 6.9 Using the global Statement to Remember the Value of a Variable Between Function Calls
  1: <html>
  2: <head>
  3: <title>Listing 6.9</title>
  4: </head>
  5: <body>
  6: <?php
  7: $num_of_calls = 0;
  8: function numberedHeading( $txt ) {
  9:     global $num_of_calls;
 10:     $num_of_calls++;
 11:     print "<h1>$num_of_calls. $txt</h1>";
 12: }
 13: numberedHeading("Widgets");
 14: print("We build a fine range of widgets<p>");
 15: numberedHeading("Doodads");
 16: print("Finest in the world<p>");
 17: ?>
 18: </body>
 19: </html>

Put these lines into a text file called numberedheading.php, and place this file in your Web server document root. When you access this script through your Web browser, it should look like Figure 6.6.

Figure 6.6. Using the global statement to keep track of the number of times a function has been called.


This does the job. We declare a variable, $num_of_calls, in line 7, outside the function numberedHeading(). We make this variable available to the function using the global statement in line 9.

Every time numberedHeading() is called, $num_of_calls is incremented (line 10). We can then print out a heading complete with a heading number.

This is not the most elegant solution, however. Functions that use the global statement cannot be read as standalone blocks of code. In reading or reusing them, we need to look out for the global variables that they manipulate.

This is where the static statement can be useful. If you declare a variable within a function in conjunction with the static statement, the variable remains local to the function, and the function "remembers" the value of the variable from execution to execution. Listing 6.10 adapts the code from Listing 6.9 to use the static statement.

Listing 6.10 Using the static Statement to Remember the Value of a Variable Between Function Calls
  1: <html>
  2: <head>
  3: <title>Listing 6.10</title>
  4: </head>
  5: <body>
  6: <?php
  7: function numberedHeading( $txt ) {
  8:      static $num_of_calls = 0;
  9:      $num_of_calls++;
 10:      print "<h1>$num_of_calls. $txt</h1>";
 11: }
 12: numberedHeading("Widgets");
 13: print("We build a fine range of widgets<p>");
 14: numberedHeading("Doodads");
 15: print("Finest in the world<p>");
 16: ?>
 17: </body>
 18: </html>

numberedHeading() has become entirely self-contained. When we declare the $num_of_calls variable on line 8, we assign an initial value to it. This assignment is made when the function is first called on line 12. This initial assignment is ignored when the function is called a second time on line 14. Instead, the code remembers the previous value of $num_of_calls. We can now paste the numberedHeading() function into other scripts without worrying about global variables. Although the output of Listing 6.10 is exactly the same as that of Listing 6.9 (try it and see!), we have made the code more elegant.

    Part III: Getting Involved with the Code