Scope was discussed a bit in Chapter 2, and now that discussion expands. You can create variables in a PHP script both external to a function (outside the function) and internal to the function (inside the function). If you create a variable named $total_sales outside a function, for example, and then pass its value inside a function that performs processing on an internally created variable named $total_sales, you have two distinct variables named $total_sales in existence in your script.Obviously, this situation is not going to work unless the two variables stay separate. So PHP uses the concept of scope (like so many other languages), and differentiates between the two variables so it doesn't get mixed up.
If you think about it, there are many situations where it would be convenient to use variables with the same name in one script or program. Scope allows PHP to work with two variables of the same name, so long as they remain in their appropriate places. (In much the same way, namespaces provide a means for XML elements of the same name to work within the same XML document and still stay separate. XML namespaces are discussed in Chapter 8.)
Variables created in a PHP script have a lifetime as well as scope. A variable created inside a function stays in existence only as long as the function is processing. When the function finishes, the variable is lost, unless you define it as a static variable (more on static variables a little later in the chapter). So you say the scope of the variable is inside the function, and the lifetime of the variable is as long as the function is performing its work (a new inside variable is created each time the function is called, and it has a new life). All variables in a PHP script reach the end of their lives when the script is done.
Global and Local Variables
Variables that are created outside a function remain alive until the script ends, and are therefore said to have global scope, meaning they can be accessed from anywhere in the script. However, to access them within a function, you must use the global keyword. Placing the keyword global before the name of a variable means that you can use it within the function (but you can't then create another variable of the same name because that name is now taken within the function as well). Variables that are created inside a function are described as having local scope.
Here's an example of how local and global variables work:
<?php $global_message = "Global Message"; function addto_message($global_message) { global $global_message; $global_message .= " And More"; return $global_message; } addto_message ($global_message); echo "the global messge is " . $global_message; ?>
This example produces a statement with the value "The global message is Global Message And More" because running the function changes the value of $global_message. It only changes because the global keyword is used; it's almost like passing the argument into the function by reference.
In fact, putting the global keyword in front of a variable name inside the function does reference a superglobal array variable named $_GLOBALS. In this case, creating the variable $global_message (or any variable, for that matter) in the PHP script outside the function (and thereby with global scope) automatically sets it as part of the $_GLOBALS variable. So there are really two ways to access global variables from inside a function: by preceding their names with the global keyword (like this: global $global_message), or by using $_GLOBALS superglobal array variable (like this: $_GLOBALS[global_message]).
Creating Static Function Variables
You'll recall from Chapter 2 that creating a variable inside a function with the keyword static in front of it allows that variable to persist beyond the time the function runs. And because the static variable exists only in the local scope of the function, both the variable and its most recently accumulated value will be available next time the function runs. This can be useful anytime you want to count something that happens or is measured within the function.
For example, suppose you want to count the records returned each time records are retrieved from a database. You could write something like this:
<?php
function get_records($table)
{
//make database connection
//retrieve records
//get_record_count
static $record_count;
//set $record_count equal to number of records returned, plus any current
//value it holds
echo "current total records retrieved is " . $record_count;
//return something }
Although the example is mostly pseudo code, it shows how to set the $record_count variable so that it is static. And it should be clear that each time the function runs (at least, as long as the PHP script is running), the $record_count variable will be incremented by the number of records returned. For example, if you retrieved 20 records the first time, 30 records the second time, and 40 records the last time the function was called within a PHP script, then $record_count would be set to 90 by the end of the script. Of course, you could echo out the current record count each time, as this example did.
Here's a quick recap of global, local, and static variables:
- Global variables have values that persist throughout the whole program, but to use them inside a function you have to prefix them with the keyword global or address them using the $_GLOBALS superglobal array.
- Local variables have values that exist only inside of a function and only for the duration of one function call.
- Static variables are local variables that persist in value inside the function every time the function is called.
Next, create a small application that demonstrates how these work.
Try it Out: Demonstrating Scope
- Open your Web page editor and enter in the following:
<html> <head><title></title></head> <body> <font size=-1> <?php $global_message = "Global Message"; function my_function() { $local_message = "Local Message"; static $static_number = 0; echo "<br>the contents of global message are " . $GLOBALS["global_message"]; echo "<br>the contents of local message are " . $local_message; echo "<br>the contents of static number are " . $static_number; return $static_number = $static_number+1; } echo "<b>Calling the function for the first time:</b>"; my_function(); echo "<br><br><b>Outside the function:</b>"; echo "<br>the contents of global message are " . $global_message; echo "<br>the contents of local message are " . $local_message; echo "<br>the contents of static number are " . $static_number; echo "<br><br><b>Calling the function for the second time:</b>"; my_function(); echo "<br><br><b>Outside the function: </b>"; echo "<br>the contents of global message are " . $global_message; echo "<br>the contents of local message are " . $local_message; echo "<br>the contents of static number are " . $static_number; echo "<br><br><b>Calling the function for the third time:</b>"; my_function(); echo "<br><br><b>Outside the function:</b>"; echo "<br>the contents of global message are " . $global_message; echo "<br>the contents of local message are " . $local_message; echo "<br>the contents of static number are " . $static_number; ?> </font> </body> </html>
- Save this as scope.php. and close the file.
- Open up your browser and render scope.php.
How it Works
This program has no practical application, but given that variable scope is a difficult subject to grasp, the program emphasizes how the different types of variables work in PHP. The first line creates and assigns $global_message:
$global_message = "Global Message";
The function (named my_function) is defined:
function my_function()
{
Inside it, a local variable, called $local_message, and a static variable called $static_number, are created:
$local_message="Local Message";
static $static_number = 0;
The next three lines display the contents of the global, local, and static variables within the function:
echo "<br>the contents of global message are " . $GLOBALS["global_message"]; echo "<br>the contents of local message are " . $local_message; echo "<br>the contents of static number are " . $static_number;
The return statement alters the contents of the $static_number variable, incrementing it by 1:
return $static_number = $static_number+1;
}
The program starts by calling my_function():
echo "<b>Calling the function for the first time:</b>";
my_function();
You see the contents of the global, local, and static variables, which are "GlobalMessage", "Local Message", and 0 inside the function. Once the function is finished running, the contents of these variables are shown outside the function. You may get undefined variable warnings, depending on what level of error reporting you have set—this is normal if you think about it. $local_message and $static_number are only defined within the function body, and so do not exist outside of it:
echo "<br><br><b>Outside the function:</b>";
echo "<br>the contents of global message are " . $global_message;
echo "<br>the contents of local message are " . $local_message;
echo "<br>the contents of static number are " . $static_number;
The function is called several more times, and each time shows what the variables inside the function are set to, as well as what they are outside the function. The $static_number variable inside the function is the only one that changes.
Nesting
It's possible to create and call functions within functions. This is called nesting, but under most circumstances this capability isn't very useful. You've already looked at calling functions from within functions, and by itself this is helpful. But to define and call a function inside a function can lead to problems.
For example, you could write a parent function that would, within itself, define another function (call it the child function). The problem is that if you call the parent function twice, you're in effect trying to define the child function twice, and you can't redefine existing functions, so the script would fail. Mostof the time you're better off just defining functions separately.
But there is another situation (besides using functions for switching, as discussed a few sections ago) when it would be useful to call a function from inside a function: recursion (a function calling itself).
Recursion
Calling a function from within itself is known as recursion. Calling a function recursively creates a looping structure, in that the function will continue to call itself until a condition is met. However, you have to create the condition explicitly within the lines of code in the function, and if you don't ensure that there is some kind of "stop" value that will be reached no matter what, your function may recurse (and you may curse a few times yourself) infinitely. Here's a quick example.
Try it Out: Calling a Function Recursively
- Start up your Web page editor and type the following:
<html> <head></head> <body> <?php if {$._POST[posted]) { $num - $_POST[num]; function, recursion ($num) { if ($num <= 1) { return 1; } else{ return $num * recursion($num-1); } } echo "The factorial of " . $num . " is " . (recursion($num)); } ?> <form method="POST" action="recursion.php"> <input type="hidden" name="posted" value="true"> I would like to know the factorial of <input name="num" type="text"> <br> <br> <input type="submit" value="Get Factorial"> </form> </body> </html>
- Save this as recursion.php and close the file.
- Open recursion.php in your browser.
Of course, once you have chosen your value and pressed the Get Factorial button, the faithful recursive example tells you the answer.
How it Works
First declare the recursion function, and give it $num_value as an argument:
<?php if ($_POST[posted]) { $num = $_POST[num]; function recursion($num) { if ($num <= 1) { return 1; } else { return $num * recursion($num-1); } } echo "The factorial of " . $num . " is " . (recursion($num)); } ?>
Next, make sure that $num has not been given as zero or one; if it has, you return 1 (you already know that the factorial of one is one). If you have a number greater than one, execute the recursive part of the function. Finally, you echo the result.
Each time through the loop you not only multiply by the most recent number (that's the recursive part), but you also use the steadily dwindling value to make sure the loop eventually ends. (It's easy to break the script with larger numbers, and that it doesn't work with negative numbers, but for this example, it works well enough.)
