2.6 User-Defined Functions
User-defined functions provide a way
to group together related statements into a cohesive block. For
reusable code, a function saves duplicating statements and makes
maintenance of the code easier. Consider an example of a simple
user-developed function as shown in Example 2-3.
Example 2-3. A user-defined function to output bold text
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"The script defines the function bold( ), which
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Simple Function Call</title>
</head>
<body bgcolor="#ffffff">
<?php
function bold($string)
{
print "<b>" . $string . "</b>";
}
// First example function call (with a static string)
print "this is not bold ";
bold("this is bold ");
print "this is again not bold ";
// Second example function call (with a variable)
$myString = "this is bold";
bold($myString);
?>
</body></html>
takes one parameter, $string, and prints that
string prefixed by a bold <b> tag and
suffixed with a </b> tag. The parameter
$string is a variable that is available in the
body of the function, and the value of $string is
set when the function is called. As shown in the example, the
function can be called with a string literal expression or a variable
as the parameter.Functions can also return values. For example, consider the following
code fragment that declares and uses a function heading(
), which returns a string using the
return statement:
function heading($text, $headingLevel)The function takes two parameters: the text of a heading and a
{
switch ($headingLevel)
{
case 1:
$result = "<h1>$text</h1>";
break;
case 2:
$result = "<h2>$text</h2>";
break;
case 3:
$result = "<h3>$text</h3>";
break;
default:
$result = "<p><b>$text</b></p>";
}
return($result);
}
$test = "User-defined Functions";
print heading($test, 2);
heading level. Based on the value of
$headingLevel, the function builds the HTML
suitable to display the heading. The example outputs the string:
<h2>User-defined Functions</h2>The variable that is returned by a return
statement can optionally be placed in parentheses: the statements
return($result) and return
$result are identical.
2.6.1 Parameter Types and Return Types
The parameter and return types of a
function aren't declared when the function is
defined. PHP allows parameters of any type to be passed to the
function, and as with variables, the return type is determined when a
result is actually returned. Consider a simple function that divides
two numbers:
function divide($a, $b)The value returned from the function divide( )
{
return ($a/$b);
}
is the value of the expression ($a/$b). The type
that is returned depends on the parameters passed to
divide( ). For example:
$c = divide(4, 2); // assigns an integer value = 2If the types of parameters passed to the function are critical, they
$c = divide(3, 2); // assigns a float value = 1.5
$c = divide(4.0, 2.0); // assigns a float value = 2.0
should be tested as shown earlier in Section 2.5.1.The return statement causes the execution of the
function to end. To illustrate this, consider an improved
divide( ) function definition that tests the
parameter $b to avoid divide-by-zero errors:
function divide($a, $b)If $b is 0, then the function returns
{
if ($b == 0)
return false;
return ($a/$b);
}
false and the division of $a/$b
is never executed.The return statement can also be used to exit from
functions that don't return values. Consider the
following definition of bold( ) that simply
prints the parameter $string without any bold
mark-up when passed non-string values:
function bold($string)
{
if (! is_string($string))
{
print $string;
return;
}
print "<b>" . $string . "</b>";
}
2.6.2 Variable Scope
Variables
used inside a function are different from those used outside a
function. The variables used inside the function are limited to use
within the function. This is called the scope of
the variable. There are exceptions to this rule, which are discussed
later in this section. Consider an example that illustrates variable
scope:
function doublevalue($var)This example outputs the string:
{
$temp = $var * 2;
}
$variable = 5;
doublevalue($variable);
print "\$temp is: $temp";
$temp is:with no value for $temp. The scope of the variable
$temp is local to the function
doublevalue( ) and is discarded when the
function returns.The PHP script engine doesn't complain about an
undeclared variable being used. It just assumes the variable is
empty. However, this use of an undefined variable can be detected by
configuring the error-reporting settings. Error reporting is
discussed in Chapter 14.The easiest way to use a value that is local to a function elsewhere
in a script is to return the value from the function with the
return statement. The calling script can simply
assign the returned value to a local variable. The following example
does this:
function doublevalue($var)The example prints:
{
$returnVar = $var * 2;
return($returnVar);
}
$variable = 5;
$temp = doublevalue($variable);
print "\$temp is: $temp";
$temp is: 10You could have still used the variable name $temp
inside the function doublevalue( ). However, the
$temp inside the function is a different variable
from the $temp outside the function. The general
rule is that variables used exclusively within functions are local to
the function, regardless of whether an identically named variable is
used elsewhere. There are three exceptions to this general rule:
variables passed by reference, variables declared
global in the function, and superglobals that
contain user and environment values and are automatically created by
PHP at runtime. Global variables are discussed in the next section,
and superglobals are discussed in Chapter 6.
2.6.2.1 Global variables
If you want to use the same variable
everywhere in your code, including within functions, you can do so
with the global statement. The
global statement declares a variable within a
function as being the same as the variable that is used outside of
the function. Consider this example:
function doublevalue( )Because $temp is declared inside the function as
{
global $temp;
$temp = $temp * 2;
}
$temp = 5;
doublevalue( );
print "\$temp is: $temp";
global, the variable $temp used
in doublevalue( ) is a global variable that can
be accessed outside the function. Because the variable
$temp can be seen outside the function, the script
prints:
$temp is: 10A word of caution: avoid overuse of global as it
makes for confusing code.
|
that a return statement can only pass back one
value. An alternative to using global is to return
an array of valuesthis approach becomes clear when we discuss
arrays in Chapter 3. A better approach is to
pass parameters by reference instead of by value, a practice
described later.
2.6.2.2 Static variables
Variables can also be declared
within a function as static. The static variable is available only in
the scope of the function, but the value is not lost between function
calls. Consider simple function count( ) that
declares a static counter variable $count:
function count( )The first time the function count( ) is called,
{
static $count = 0;
$count++;
return $count;
}
// prints 1
print count( );
// prints 2
print count( );
the static variable $count is set to zero, and
incremented. The value of $count is maintained for
subsequent calls.
2.6.3 Passing Variables to Functions
By default, variables are passed
to functions by value, not by reference. Consider an example:
function doublevalue($var)This produces the output:
{
$var = $var * 2;
}
$variable = 5;
doublevalue($variable);
print "\$variable is: $variable";
$variable is: 5The parameter $variable that is passed to the
function doublevalue( ) isn't
changed by the function. What actually happens is that the value 5 is
passed to the function, doubled to be 10, and the result lost
forever! The value is passed to the function, not the variable
itself.
2.6.3.1 Passing parameters by reference
An
alternative to returning a result or using a global variable is to
pass a reference to a variable as a parameter to
the function. This means that any changes to the variable within the
function affect the original variable. Consider this example:
function doublevalue(&$var)This prints:
{
$var = $var * 2;
}
$variable = 5;
doublevalue($variable);
print "\$variable is: $variable";
$variable is: 10The only difference between this example and the previous one is that
the parameter $var to the function
doublevalue( )
is prefixed with an ampersand
character: &$var. The effect is a bit to hard
to understand unless one learns low-level computer languages, but it
means that the parameter doesn't contain the value
of the variableinstead, it points to where the variable is
stored in memory. The result is that changes to
$var in the function affect the original variable
$variable outside the function.If a parameter is defined as a reference, you can't
pass the function a literal expression as that parameter because the
function expects to modify a variable. PHP reports an error when the
following is executed:
function doublevalue(&$var)
{
$var = $var * 2;
}
// The following line causes an error
doublevalue(5);
2.6.3.2 Assigning by reference
Referencing with the ampersand can
also be used when assigning variables, which allows the memory
holding a value to be accessed from more than one variable. This
example illustrates the idea:
$x = 10;This fragment prints:
$y = &$x;
$y++;
print $x;
print $y;
11Because $y is a reference to
11
$x, any change to $y affects
$x. In effect, they are the same variable. The
reference $y can be removed with:
unset($y);This has no effect on $x or its value.Assigning variables with a reference to another variable can also be
done with the reference assignment operator =&
with exactly the same outcome as shown in the previous example. The
following fragment sets up three
variables$x, $y, and
$zthat all point to the same value:
$x = 10;
// Use the reference assignment operator =& to assign a reference to $x
$y =& $x;
// Use the assignment operator = to copy a reference to $x
$z = &$x;
$x = 100;
// Prints "x = 100, y = 100, z = 100"
print "x = {$x}, y = {$y}, z = {$z}";
2.6.3.3 Default parameter values
PHP allows functions to be defined with
default values for parameters. A default value is simply supplied in
the parameter list using the = sign. Consider the
heading( ) function described earlier; here we
modify the function definition to include a default value:
function heading($text, $headingLevel = 2)When calls are made to the heading( ) function,
{
switch ($headingLevel)
{
case 1:
$result = "<h1>$text</h1>";
break;
case 2:
$result = "<h2>$text</h2>";
break;
case 3:
$result = "<h3>$text</h3>";
break;
default:
$result = "<p><b>$text</b></p>";
}
return($result);
}
$test = "User-defined Functions";
print heading($test);
the second argument can be omitted, and the default value 2 is
assigned to the $headingLevel variable.
2.6.4 Reusing Functions with Include and Require Files
It's valuable to be
able to reuse functions in many scripts. PHP provides the
include and require statements
that allow you to reuse PHP scripts containing statements, function
definitions, and even static HTML.If you decide to reuse the bold( ) function from
Example 2-3 in more than one script, you can store
it in a separate include file
. For example, you can create a file
called functions.inc and put the bold(
) function in the file:
<?php
function bold($string)
{
print "<b>" . $string . "</b>";
}
?>
|
bold( ) function:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"Include files can also be used to incorporate resources such as
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Simple Function Call</title>
</head>
<body bgcolor="#ffffff">
<?php
include "functions.inc";
// First example function call (with a string expression)
print "this is not bold ";
bold("this is bold ");
print "this is again not bold ";
// Second example function call (with a variable)
$myString = "this is bold";
bold($myString);
?>
</body></html>
static HTML or a set of variable initializations. The following
example could be written to the file release.inc
and included in all the scripts of an application:
<!-- Beta Release Only -->Both include and require read
<?php
$showDebug = true;
?>
external include files, the only difference is in the behavior when a
file can't be included: include
provides a warning whereas require terminates the
script with a fatal error.When you are including a file that contains user-defined functions,
or other mandatory content, you should use the
require
directive. We use the
require directive in all of our code.The include and require
statements can be treated in the same way as other statements. For
example, you can conditionally include different files using the
following code fragment:
if ($netscape == true)The file is included only if the include statement
{
require "netscape.inc";
}
else
{
require "other.inc";
}
is executed in the script. The braces used in this example are
necessary: if they are omitted, the example doesn't
behave as expected.Scripts can include more than one include file, and include files can
themselves include other files. Writing scripts that use
include or require can lead to
an include file being included and evaluated twice. To avoid problems
with variable reassignments and function redefinitions, PHP provides
the include_once or
require_once constructs statements that ensure
that the contents of the file are included only once.
2.6.4.1 Managing include files
As you
develop reusable code, you should consider how you will arrange your
include files. By default, when a file is included using the
include or require statements,
PHP searches for the file in the same directory as the script being
executed. You can include files in other directories by specifying a
file path in the include or
require statements. The following example shows
how relative and absolute file paths can be used:
// a relative file pathThe paths can be specified with forward slashes for both Unix and
require "../inc/myFunctions.php";
// an absolute file path
require "/library/database/db.inc";
Microsoft Windows environments, allowing scripts to be moved from one
environment to another. However, using paths can make it difficult to
change the directory structure of your application.A more sophisticated, and flexible alternative to accessing include
files is to set the include_path parameter defined
in the php.ini configuration file. One or more
directories can be specified in the include_path
parameter, and when set, PHP will search for include files relative
to those directories. The following extract from the
php.ini file shows how to set the
include_path parameter:
;;;;;;;;;;;;;;;;;;;;;;;;;Path specifications for this parameter are system specific. Unix
; Paths and Directories ;
;;;;;;;;;;;;;;;;;;;;;;;;;
; UNIX: "/path1:/path2"
;include_path = ".:/php/includes:/usr/local/php/projectx"
;
; Windows: "\path1;\path2"
include_path = ".;c:\php\includes;d:\php\projectx"
paths use the forward slash and are separated with the colon (:)
character, while Microsoft Windows paths use the backslash and are
separated by semi colons (;).The php.ini configuration file defines many
parameters that are used to define aspects of PHP's
behavior. Whenever you change php.ini, you need
to restart your Apache web server so that the changes are re-read;
instructions for restarting are in Appendix A.If you set the include_path parameter,
include and require directives
need only specify a path relative to a directory listed in the
include_path. For example, if the
include_path is set to point at
/usr/local/php/projectx, and you have an include
file security.inc that's stored
in /usr/local/php/projectx/security, you only
need to add:
include "security/security.inc";to your script file. The PHP engine will check the directory
/usr/local/php/projectx, and locate the
subdirectory security and its include file.
Include files that are placed in directories outside of the web
server's document root are protected from accessed
via the web server. In Chapter 6 we describe
how to protect include files that are under the web server root
directory.For a large project, you might place the project-specific code into
one directory, while keeping reusable code in another; this is the
approach we use in our case study, Hugh and
Dave's Online Wines, as we describe in
Chapter 15.