Chapter 2. Language Basics

This chapter provides a whirlwind tour of the core PHP language, covering such basic topics as data types, variables, operators, and flow-control statements. PHP is strongly influenced by other programming languages, such as Perl and C, so if you’ve had experience with those languages, PHP should be easy to pick up. If PHP is one of your first programming languages, don’t panic. We start with the basic units of a PHP program and build up your knowledge from there.

Lexical Structure

The lexical structure of a programming language is the set of basic rules that governs how you write programs in that language. It is the lowest-level syntax of the language and specifies such things as what variable names look like, what characters are used for comments, and how program statements are separated from each other.

Case Sensitivity

The names of user-defined classes and functions, as well as built-in constructs and keywords (such as echo, while, class, etc.), are case-insensitive. Thus, these three lines are equivalent:

echo("hello, world");
ECHO("hello, world");
EcHo("hello, world");

Variables, on the other hand, are case-sensitive. That is, $name, $NAME, and $NaME are three different variables.

Statements and Semicolons

A statement is a collection of PHP code that does something. It can be as simple as a variable assignment or as complicated as a loop with multiple exit points. Here is a small sample of PHP statements, including function calls, some variable data assignments, and an if statement:

echo "Hello, world";
myFunction(42, "O'Reilly");
$a = 1;
$name = "Elphaba";
$b = $a / 25.0;
if ($a == $b) {
 echo "Rhyme? And Reason?";
}

PHP uses semicolons to separate simple statements. A compound statement that uses curly braces to mark a block of code, such as a conditional test or loop, does not need a semicolon after a closing brace. Unlike in other languages, in PHP the semicolon before the closing brace is not optional:

if ($needed) {
 echo "We must have it!"; // semicolon required here
} // no semicolon required here after the brace

The semicolon, however, is optional before a closing PHP tag:

<?php
if ($a == $b) {
 echo "Rhyme? And Reason?";
}
echo "Hello, world" // no semicolon required before closing tag
?>

It’s good programming practice to include optional semicolons, as they make it easier to add code later.

Whitespace and Line Breaks

In general, whitespace doesn’t matter in a PHP program. You can spread a statement across any number of lines, or lump a bunch of statements together on a single line. For example, this statement:

raisePrices($inventory, $inflation, $costOfLiving, $greed);

could just as well be written with more whitespace:

raisePrices (
 $inventory ,
 $inflation ,
 $costOfLiving ,
 $greed
) ;

or with less whitespace:

raisePrices($inventory,$inflation,$costOfLiving,$greed);

You can take advantage of this flexible formatting to make your code more readable (by lining up assignments, indenting, etc.). Some lazy programmers take advantage of this freeform formatting and create completely unreadable code—this is not recommended.

Comments

Comments give information to people who read your code, but they are ignored by PHP at execution time. Even if you think you’re the only person who will ever read your code, it’s a good idea to include comments in your code—in retrospect, code you wrote months ago could easily look as though a stranger wrote it.

A good practice is to make your comments sparse enough not to get in the way of the code itself but plentiful enough that you can use the comments to tell what’s happening. Don’t comment obvious things, lest you bury the comments that describe tricky things. For example, this is worthless:

$x = 17; // store 17 into the variable $x

whereas the comments on this complex regular expression will help whoever maintains your code:

// convert &#nnn; entities into characters

$text = preg_replace('/&#([0-9])+;/', "chr('\1')", $text);

PHP provides several ways to include comments within your code, all of which are borrowed from existing languages such as C, C++, and the Unix shell. In general, use C-style comments to comment out code, and C++-style comments to comment on code.

Shell-style comments

When PHP encounters a hash mark character (#) within the code, everything from the hash mark to the end of the line or the end of the section of PHP code (whichever comes first) is considered a comment. This method of commenting is found in Unix shell scripting languages and is useful for annotating single lines of code or making short notes.

Because the hash mark is visible on the page, shell-style comments are sometimes used to mark off blocks of code:

#######################
## Cookie functions
#######################

Sometimes they’re used before a line of code to identify what that code does, in which case they’re usually indented to the same level as the code for which the comment is intended:

if ($doubleCheck) {
 # create an HTML form requesting that the user confirm the action
 echo confirmationForm();
}

Short comments on a single line of code are often put on the same line as the code:

$value = $p * exp($r * $t); # calculate compounded interest

When you’re tightly mixing HTML and PHP code, it can be useful to have the closing PHP tag terminate the comment:

<?php $d = 4; # Set $d to 4. ?> Then another <?php echo $d; ?>
Then another 4

C++ comments

When PHP encounters two slashes (//) within the code, everything from the slashes to the end of the line or the end of the section of code, whichever comes first, is considered a comment. This method of commenting is derived from C++. The result is the same as the shell comment style.

Here are the shell-style comment examples, rewritten to use C++ comments:

////////////////////////
// Cookie functions
////////////////////////

if ($doubleCheck) {
 // create an HTML form requesting that the user confirm the action
 echo confirmationForm();
}

$value = $p * exp($r * $t); // calculate compounded interest

<?php $d = 4; // Set $d to 4. ?> Then another <?php echo $d; ?>
Then another 4

C comments

While shell-style and C++-style comments are useful for annotating code or making short notes, longer comments require a different style. Therefore, PHP supports block comments whose syntax comes from the C programming language. When PHP encounters a slash followed by an asterisk (/*), everything after that, until it encounters an asterisk followed by a slash (*/), is considered a comment. This kind of comment, unlike those shown earlier, can span multiple lines.

Here’s an example of a C-style multiline comment:

/* In this section, we take a bunch of variables and
 assign numbers to them. There is no real reason to
 do this, we're just having fun.
*/
$a = 1;
$b = 2;
$c = 3;
$d = 4;

Because C-style comments have specific start and end markers, you can tightly integrate them with code. This tends to make your code harder to read and is discouraged:

/* These comments can be mixed with code too,
see? */ $e = 5; /* This works just fine. */

C-style comments, unlike the other types, can continue past the end PHP tag markers. For example:

<?php
$l = 12;
$m = 13;
/* A comment begins here
?>
<p>Some stuff you want to be HTML.</p>
<?= $n = 14; ?>
*/
echo("l=$l m=$m n=$n
");
?><p>Now <b>this</b> is regular HTML...</p>
l=12 m=13 n=
<p>Now <b>this</b> is regular HTML...</p>

You can indent comments as you like:

/* There are no
 special indenting or spacing
 rules that have to be followed, either.


 */

C-style comments can be useful for disabling sections of code. In the following example, we’ve disabled the second and third statements, as well as the inline comment, by including them in a block comment. To enable the code, all we have to do is remove the comment markers:

$f = 6;
/*
$g = 7; # This is a different style of comment
$h = 8;
*/

However, you have to be careful not to attempt to nest block comments:

$i = 9;
/*
$j = 10; /* This is a comment */
$k = 11;
Here is some comment text.
*/

In this case, PHP tries (and fails) to execute the (non)statement Here is some comment text and returns an error.

Literals

A literal is a data value that appears directly in a program. The following are all literals in PHP:

2001
0xFE
1.4142
"Hello World"
'Hi'
true
null

Identifiers

An identifier is simply a name. In PHP, identifiers are used to name variables, functions, constants, and classes. The first character of an identifier must be an ASCII letter (uppercase or lowercase), the underscore character (_), or any of the characters between ASCII 0x7F and ASCII 0xFF. After the initial character, these characters and the digits 0–9 are valid.

Variable names

Variable names always begin with a dollar sign ($) and are case-sensitive. Here are some valid variable names:

$bill
$head_count
$MaximumForce
$I_HEART_PHP
$_underscore
$_int

Here are some illegal variable names:

$not valid
$|
$3wa

These variables are all different due to case sensitivity:

$hot_stuff $Hot_stuff $hot_Stuff $HOT_STUFF

Function names

Function names are not case-sensitive (functions are discussed in more detail in Chapter 3). Here are some valid function names:

tally
list_all_users
deleteTclFiles
LOWERCASE_IS_FOR_WIMPS
_hide

These function names all refer to the same function:

howdy HoWdY HOWDY HOWdy howdy

Class names

Class names follow the standard rules for PHP identifiers and are also not case-sensitive. Here are some valid class names:

Person
account

The class name stdClass is a reserved class name.

Constants

A constant is an identifier for a value that will not be changed; scalar values (Boolean, integer, double, and string) and arrays can be constants. Once set, the value of a constant cannot change. Constants are referred to by their identifiers and are set using the define() function:

define('PUBLISHER', "O'Reilly Media");
echo PUBLISHER;

Keywords

A keyword (or reserved word) is a word set aside by the language for its core functionality—you cannot give a function, class, or constant the same name as a keyword. Table 2-1 lists the keywords in PHP, which are case-insensitive.

Table 2-1. PHP core language keywords
__CLASS__
__DIR__
__FILE__
__FUNCTION__
__LINE__
__METHOD__
__NAMESPACE__
__TRAIT__
__halt_compiler()
abstract
and
array()
as
break
callable
case
catch
class
clone
const
continue
declare
default
die()
do
echo
else
elseif
empty()
enddeclare
endfor
endforeach
endif
endswitch
endwhile
eval()
exit()
extends
final
finally
for
foreach
function
global
goto
if
implements
include
include_once
instanceof
insteadof
interface
isset()
list()
namespace
new
or
print
private
protected
public
require
require_once
return
static
switch
throw
trait
try
unset()
use
var
while
xor
yield
yield from

In addition, you cannot use an identifier that is the same as a built-in PHP function. For a complete list of these, see the appendix.

Data Types

PHP provides eight types of values, or data types. Four are scalar (single-value) types: integers, floating-point numbers, strings, and Booleans. Two are compound (collection) types: arrays and objects. The remaining two are special types: resource and NULL. Numbers, Booleans, resources, and NULL are discussed in full here, while strings, arrays, and objects are big enough topics that they get their own chapters (Chapter 4, Chapter 5, and Chapter 6, respectively).

Integers

Integers are whole numbers, such as 1, 12, and 256. The range of acceptable values varies according to the details of your platform but typically extends from −2,147,483,648 to +2,147,483,647. Specifically, the range is equivalent to the range of the long data type of your C compiler. Unfortunately, the C standard doesn’t specify what range that long type should have, so on some systems you might see a different integer range.

Integer literals can be written in decimal, octal, binary, or hexadecimal. Decimal values are represented by a sequence of digits, without leading zeros. The sequence may begin with a plus (+) or minus () sign. If there is no sign, positive is assumed. Examples of decimal integers include the following:

1998
−641
+33

Octal numbers consist of a leading 0 and a sequence of digits from 0 to 7. Like decimal numbers, octal numbers can be prefixed with a plus or minus. Here are some example octal values and their equivalent decimal values:

0755 // decimal 493
+010 // decimal 8

Hexadecimal values begin with 0x, followed by a sequence of digits (0–9) or letters (A–F). The letters can be upper- or lowercase but are usually written in capitals. As with decimal and octal values, you can include a sign in hexadecimal numbers:

0xFF // decimal 255
0x10 // decimal 16
-0xDAD1 // decimal −56017

Binary numbers begin with 0b, followed by a sequence of digits (0 and 1). As with other values, you can include a sign in binary numbers:

0b01100000 // decimal 96
0b00000010 // decimal 2
-0b10 // decimal −2

If you try to store a variable that is too large to be stored as an integer or is not a whole number, it will automatically be turned into a floating-point number.

Use the is_int() function (or its is_integer() alias) to test whether a value is an integer:

if (is_int($x)) {
 // $x is an integer
}

Floating-Point Numbers

Floating-point numbers (often referred to as “real” numbers) represent numeric values with decimal digits. Like integers, their limits depend on your machine’s details. PHP floating-point numbers are equivalent to the range of the double data type of your C compiler. Usually, this allows numbers between 1.7E−308 and 1.7E+308 with 15 digits of accuracy. If you need more accuracy or a wider range of integer values, you can use the BC or GMP extensions.

PHP recognizes floating-point numbers written in two different formats. There’s the one we all use every day:

3.14
0.017
-7.1

but PHP also recognizes numbers in scientific notation:

0.314E1 // 0.314*10^1, or 3.14
17.0E-3 // 17.0*10^(-3), or 0.017

Floating-point values are only approximate representations of numbers. For example, on many systems 3.5 is actually represented as 3.4999999999. This means you must take care to avoid writing code that assumes floating-point numbers are represented completely accurately, such as directly comparing two floating-point values using ==. The normal approach is to compare to several decimal places:

if (intval($a * 1000) == intval($b * 1000)) {
 // numbers equal to three decimal places
}

Use the is_float() function (or its is_real() alias) to test whether a value is a floating-point number:

if (is_float($x)) {
 // $x is a floating-point number
}

Strings

Because strings are so common in web applications, PHP includes core-level support for creating and manipulating strings. A string is a sequence of characters of arbitrary length. String literals are delimited by either single or double quotes:

'big dog'
"fat hog"

Variables are expanded (interpolated) within double quotes, while within single quotes they are not:

$name = "Guido";
echo "Hi, $name <br/>";
echo 'Hi, $name';
Hi, Guido
Hi, $name

Double quotes also support a variety of string escapes, as listed in Table 2-2.

Table 2-2. Escape sequences in double-quoted strings
Escape sequence Character represented
" Double quotes
Newline
Carriage return
Tab
\ Backslash
$ Dollar sign
{ Left brace
} Right brace
[ Left bracket
] Right bracket
through 777 ASCII character represented by octal value
x0 through xFF ASCII character represented by hex value

A single-quoted string recognizes \ to get a literal backslash and ' to get a literal single quote:

$dosPath = 'C:\WINDOWS\SYSTEM';
$publisher = 'Tim O'Reilly';
echo "$dosPath $publisher";
C:WINDOWSSYSTEM Tim O'Reilly

To test whether two strings are equal, use the == (double equals) comparison operator:

if ($a == $b) {
 echo "a and b are equal";
}

Use the is_string() function to test whether a value is a string:

if (is_string($x)) {
 // $x is a string
}

PHP provides operators and functions to compare, disassemble, assemble, search, replace, and trim strings, as well as a host of specialized string functions for working with HTTP, HTML, and SQL encodings. Because there are so many string-manipulation functions, we’ve devoted a whole chapter (Chapter 4) to covering all the details.

Booleans

A Boolean value represents a “truth value”—it says whether something is true or not. Like most programming languages, PHP defines some values as true and others as false. Truthfulness and falseness determine the outcome of conditional code such as:

if ($alive) { ... }

In PHP, the following values all evaluate to false:

  • The keyword false

  • The integer 0

  • The floating-point value 0.0

  • The empty string ("") and the string "0"

  • An array with zero elements

  • The NULL value

A value that is not false is true, including all resource values (which are described later in the section “Resources”).

PHP provides true and false keywords for clarity:

$x = 5; // $x has a true value
$x = true; // clearer way to write it
$y = ""; // $y has a false value
$y = false; // clearer way to write it

Use the is_bool() function to test whether a value is a Boolean:

if (is_bool($x)) {
 // $x is a Boolean
}

Arrays

An array holds a group of values, which you can identify by position (a number, with zero being the first position) or some identifying name (a string), called an associative index:

$person[0] = "Edison";
$person[1] = "Wankel";
$person[2] = "Crapper";

$creator['Light bulb'] = "Edison";
$creator['Rotary Engine'] = "Wankel";
$creator['Toilet'] = "Crapper";

The array() construct creates an array. Here are two examples:

$person = array("Edison", "Wankel", "Crapper");
$creator = array('Light bulb' => "Edison",
 'Rotary Engine' => "Wankel",
 'Toilet' => "Crapper");

There are several ways to loop through arrays, but the most common is a foreach loop:

foreach ($person as $name) {
 echo "Hello, {$name}<br/>";
}

foreach ($creator as $invention => $inventor) {
 echo "{$inventor} invented the {$invention}<br/>";
}
Hello, Edison
Hello, Wankel
Hello, Crapper
Edison created the Light bulb
Wankel created the Rotary Engine
Crapper created the Toilet

You can sort the elements of an array with the various sort functions:

sort($person);
// $person is now array("Crapper", "Edison", "Wankel")

asort($creator);
// $creator is now array('Toilet' => "Crapper",
// 'Light bulb' => "Edison",
// 'Rotary Engine' => "Wankel");

Use the is_array() function to test whether a value is an array:

if (is_array($x)) {
 // $x is an array
}

There are functions for returning the number of items in the array, fetching every value in the array, and much more. Arrays are covered in depth in Chapter 5.

Objects

PHP also supports object-oriented programming (OOP). OOP promotes clean, modular design; simplifies debugging and maintenance; and assists with code reuse. Classes are the building blocks of object-oriented design. A class is a definition of a structure that contains properties (variables) and methods (functions). Classes are defined with the class keyword:

class Person
{
 public $name = '';

 function name ($newname = NULL)
 {
 if (!is_null($newname)) {
 $this->name = $newname;
 }

 return $this->name;
 }
}

Once a class is defined, any number of objects can be made from it with the new keyword, and the object’s properties and methods can be accessed with the -> construct:

$ed = new Person;
$ed->name('Edison');
echo "Hello, {$ed->name} <br/>";
$tc = new Person;
$tc->name('Crapper');
echo "Look out below {$tc->name} <br/>";
Hello, Edison
Look out below Crapper

Use the is_object() function to test whether a value is an object:

if (is_object($x)) {
 // $x is an object
}

Chapter 6 describes classes and objects in much more detail, including inheritance, encapsulation, and introspection.

Resources

Many modules provide several functions for dealing with the outside world. For example, every database extension has at least a function to connect to the database, a function to query the database, and a function to close the connection to the database. Because you can have multiple database connections open at once, the connect function gives you something by which to identify that unique connection when you call the query and close functions: a resource (or a “handle”).

Each active resource has a unique identifier. Each identifier is a numerical index into an internal PHP lookup table that holds information about all the active resources. PHP maintains information about each resource in this table, including the number of references to (or uses of) the resource throughout the code. When the last reference to a resource value goes away, the extension that created the resource is called to perform tasks such as freeing any memory or closing any connection for that resource:

$res = database_connect(); // fictitious database connect function
database_query($res);

$res = "boo";
// database connection automatically closed because $res is redefined

The benefit of this automatic cleanup is best seen within functions, when the resource is assigned to a local variable. When the function ends, the variable’s value is reclaimed by PHP:

function search() {
 $res = database_connect();
 database_query($res);
}

When there are no more references to the resource, it’s automatically shut down.

That said, most extensions provide a specific shutdown or close function, and it’s considered good style to call that function explicitly when needed rather than to rely on variable scoping to trigger resource cleanup.

Use the is_resource() function to test whether a value is a resource:

if (is_resource($x)) {
 // $x is a resource
}

Callbacks

Callbacks are functions or object methods used by some functions, such as call_user_func(). Callbacks can also be created by the create_function() method and through closures (described in Chapter 3):

$callback = function()
{
 echo "callback achieved";
};

call_user_func($callback);

NULL

There’s only one value of the NULL data type. That value is available through the case-insensitive keyword NULL. The NULL value represents a variable that has no value (similar to Perl’s undef or Python’s None):

$aleph = "beta";
$aleph = null; // variable's value is gone
$aleph = Null; // same
$aleph = NULL; // same

Use the is_null() function to test whether a value is NULL—for instance, to see whether a variable has a value:

if (is_null($x)) {
 // $x is NULL
}

Variables

Variables in PHP are identifiers prefixed with a dollar sign ($). For example:

$name
$Age
$_debugging
$MAXIMUM_IMPACT

A variable may hold a value of any type. There is no compile-time or runtime type checking on variables. You can replace a variable’s value with another of a different type:

$what = "Fred";
$what = 35;
$what = array("Fred", 35, "Wilma");

There is no explicit syntax for declaring variables in PHP. The first time the value of a variable is set, the variable is created in memory. In other words, setting a value to a variable also functions as a declaration. For example, this is a valid complete PHP program:

$day = 60 * 60 * 24;
echo "There are {$day} seconds in a day.";
There are 86400 seconds in a day.

A variable whose value has not been set behaves like the NULL value:

if ($uninitializedVariable === NULL) {
 echo "Yes!";
}
Yes!

Variable Variables

You can reference the value of a variable whose name is stored in another variable by prefacing the variable reference with an additional dollar sign ($). For example:

$foo = "bar";
$$foo = "baz";

After the second statement executes, the variable $bar has the value "baz".

Variable References

In PHP, references are how you create variable aliases or pointers. To make $black an alias for the variable $white, use:

$black =& $white;

The old value of $black, if any, is lost. Instead, $black is now another name for the value that is stored in $white:

$bigLongVariableName = "PHP";
$short =& $bigLongVariableName;
$bigLongVariableName .= " rocks!";
print "$short is $short <br/>";
print "Long is $bigLongVariableName";
$short is PHP rocks!
Long is PHP rocks!

$short = "Programming $short";
print "$short is $short <br/>";
print "Long is $bigLongVariableName";
$short is Programming PHP rocks!
Long is Programming PHP rocks!

After the assignment, the two variables are alternate names for the same value. Unsetting a variable that is aliased does not affect other names for that variable’s value, however:

$white = "snow";
$black =& $white;
unset($white);
print $black;
snow

Functions can return values by reference (for example, to avoid copying large strings or arrays, as discussed in Chapter 3):

function &retRef() // note the &
{
 $var = "PHP";

 return $var;
}

$v =& retRef(); // note the &

Variable Scope

The scope of a variable, which is controlled by the location of the variable’s declaration, determines those parts of the program that can access it. There are four types of variable scope in PHP: local, global, static, and function parameters.

Local scope

A variable declared in a function is local to that function. That is, it is visible only to code in that function (excepting nested function definitions); it is not accessible outside the function. In addition, by default, variables defined outside a function (called global variables) are not accessible inside the function. For example, here’s a function that updates a local variable instead of a global variable:

function updateCounter()
{
 $counter++;
}

$counter = 10;
updateCounter();

echo $counter;
10

The $counter inside the function is local to that function, because we haven’t said otherwise. The function increments its private $counter variable, which is destroyed when the subroutine ends. The global $counter remains set at 10.

Only functions can provide local scope. Unlike in other languages, in PHP you can’t create a variable whose scope is a loop, conditional branch, or other type of block.

Global scope

Variables declared outside a function are global. That is, they can be accessed from any part of the program. However, by default, they are not available inside functions. To allow a function to access a global variable, you can use the global keyword inside the function to declare the variable within the function. Here’s how we can rewrite the updateCounter() function to allow it to access the global $counter variable:

function updateCounter()
{
 global $counter;
 $counter++;
}

$counter = 10;
updateCounter();
echo $counter;
11

A more cumbersome way to update the global variable is to use PHP’s $GLOBALS array instead of accessing the variable directly:

function updateCounter()
{
 $GLOBALS[‘counter’]++;
}

$counter = 10;
updateCounter();
echo $counter;
11

Static variables

A static variable retains its value between calls to a function but is visible only within that function. You declare a variable static with the static keyword. For example:

function updateCounter()
{
 static $counter = 0;
 $counter++;

 echo "Static counter is now {$counter}<br/>";
}

$counter = 10;
updateCounter();
updateCounter();

echo "Global counter is {$counter}";
Static counter is now 1
Static counter is now 2
Global counter is 10

Function parameters

As we’ll discuss in more detail in Chapter 3, a function definition can have named parameters:

function greet($name)
{
 echo "Hello, {$name}";
}

greet("Janet");
Hello, Janet

Function parameters are local, meaning that they are available only inside their functions. In this case, $name is inaccessible from outside greet().

Garbage Collection

PHP uses reference counting and copy-on-write to manage memory. Copy-on-write ensures that memory isn’t wasted when you copy values between variables, and reference counting ensures that memory is returned to the operating system when it is no longer needed.

To understand memory management in PHP, you must first understand the idea of a symbol table. There are two parts to a variable—its name (e.g., $name), and its value (e.g., "Fred"). A symbol table is an array that maps variable names to the positions of their values in memory.

When you copy a value from one variable to another, PHP doesn’t get more memory for a copy of the value. Instead, it updates the symbol table to indicate that “both of these variables are names for the same chunk of memory.” So the following code doesn’t actually create a new array:

$worker = array("Fred", 35, "Wilma");
$other = $worker; // array isn't duplicated in memory

If you subsequently modify either copy, PHP allocates the required memory and makes the copy:

$worker[1] = 36; // array is copied in memory, value changed

By delaying the allocation and copying, PHP saves time and memory in a lot of situations. This is copy-on-write.

Each value pointed to by a symbol table has a reference count, a number that represents the number of ways there are to get to that piece of memory. After the initial assignment of the array to $worker and $worker to $other, the array pointed to by the symbol table entries for $worker and $other has a reference count of 2.1 In other words, that memory can be reached two ways: through $worker or $other. But after $worker[1] is changed, PHP creates a new array for $worker, and the reference count of each array is only 1.

When a variable goes out of scope at the end of a function, such as function parameters and local variables, the reference count of its value is decreased by one. When a variable is assigned a value in a different area of memory, the reference count of the old value is decreased by one. When the reference count of a value reaches 0, its memory is released. This is reference counting.

Reference counting is the preferred way to manage memory. Keep variables local to functions, pass in values that the functions need to work on, and let reference counting take care of the memory management. If you do insist on trying to get a little more information or control over freeing a variable’s value, use the isset() and unset() functions.

To see if a variable has been set to something—even the empty string—use isset():

$s1 = isset($name); // $s1 is false
$name = "Fred";
$s2 = isset($name); // $s2 is true

Use unset() to remove a variable’s value:

$name = "Fred";
unset($name); // $name is NULL

Expressions and Operators

An expression is a bit of PHP code that can be evaluated to produce a value. The simplest expressions are literal values and variables. A literal value evaluates to itself, while a variable evaluates to the value stored in the variable. More complex expressions can be formed using simple expressions and operators.

An operator takes some values (the operands) and does something (e.g., adds them together). Operators are sometimes written as punctuation symbols—for instance, the + and familiar to us from math. Some operators modify their operands, while most do not.

Table 2-3 summarizes the operators in PHP, many of which were borrowed from C and Perl. The column labeled “P” gives the operator’s precedence; the operators are listed in precedence order, from highest to lowest. The column labeled “A” gives the operator’s associativity, which can be L (left-to-right), R (right-to-left), or N (nonassociative).

Table 2-3. PHP operators
P A Operator Operation
24 N clone, new Create new object
23 L [ Array subscript
22 R ** Exponentiation
21 R ~ Bitwise NOT
  R ++ Increment
  R −− Decrement
  R (int), (bool), (float), (string), (array), (object), (unset) Cast
  R @ Inhibit errors
20 N instanceof Type testing
19 R ! Logical NOT
18 L * Multiplication
  L / Division
  L % Modulus
17 L + Addition
  L Subtraction
  L . String concatenation
16 L << Bitwise shift left
  L >> Bitwise shift right
15 N <, <= Less than, less than or equal
  N >, >= Greater than, greater than or equal
14 N == Value equality
  N !=, <> Inequality
  N === Type and value equality
  N !== Type and value inequality
  N <=> Returns an integer based on a comparison of two operands: 0 when left and right are equal, -1 when left is less than right, and 1 when left is greater than right.
13 L & Bitwise AND
12 L ^ Bitwise XOR
11 L | Bitwise OR
10 L && Logical AND
9 L || Logical OR
8 R ?? Comparison
7 L ?: Conditional operator
6 R = Assignment
  R +=, −=, *=, /=, .=, %=, &=, |=, ^=, ~=, <<=, >>= Assignment with operation
5   yield from Yield from
4   yield Yield
3 L and Logical AND
2 L xor Logical XOR
1 L or Logical OR

Number of Operands

Most operators in PHP are binary operators; they combine two operands (or expressions) into a single, more complex expression. PHP also supports a number of unary operators, which convert a single expression into a more complex expression. Finally, PHP supports a few ternary operators that combine numerous expressions into a single expression.

Operator Precedence

The order in which operators in an expression are evaluated depends on their relative precedence. For example, you might write:

2 + 4 * 3

As you can see in Table 2-3, the addition and multiplication operators have different precedence, with multiplication higher than addition. So the multiplication happens before the addition, giving 2 + 12, or 14, as the answer. If the precedence of addition and multiplication were reversed, 6 * 3, or 18, would be the answer.

To force a particular order, you can group operands with the appropriate operator in parentheses. In our previous example, to get the value 18, you can use this expression:

(2 + 4) * 3

It is possible to write all complex expressions (expressions containing more than a single operator) simply by putting the operands and operators in the appropriate order so that their relative precedence yields the answer you want. Most programmers, however, write the operators in the order that they feel makes the most sense to them, and add parentheses to ensure it makes sense to PHP as well. Getting precedence wrong leads to code like:

$x + 2 / $y >= 4 ? $z : $x << $z

This code is hard to read and is almost definitely not doing what the programmer expected it to do.

One way many programmers deal with the complex precedence rules in programming languages is to reduce precedence down to two rules:

  • Multiplication and division have higher precedence than addition and subtraction.

  • Use parentheses for anything else.

Operator Associativity

Associativity defines the order in which operators with the same order of precedence are evaluated. For example, look at:

2 / 2 * 2

The division and multiplication operators have the same precedence, but the result of the expression depends on which operation we do first:

2 / (2 * 2) // 0.5
(2 / 2) * 2 // 2

The division and multiplication operators are left-associative; this means that in cases of ambiguity, the operators are evaluated from left to right. In this example, the correct result is 2.

Implicit Casting

Many operators have expectations of their operands—for instance, binary math operators typically require both operands to be of the same type. PHP’s variables can store integers, floating-point numbers, strings, and more, and to keep as much of the type details away from the programmer as possible, PHP converts values from one type to another as necessary.

The conversion of a value from one type to another is called casting. This kind of implicit casting is called type juggling in PHP. The rules for the type juggling done by arithmetic operators are shown in Table 2-4.

Table 2-4. Implicit casting rules for binary arithmetic operations
Type of first operand Type of second operand Conversion performed
Integer Floating point The integer is converted to a floating-point number.
Integer String The string is converted to a number; if the value after conversion is a floating-point number, the integer is converted to a floating-point number.
Floating point String The string is converted to a floating-point number.

Some other operators have different expectations of their operands, and thus have different rules. For example, the string concatenation operator converts both operands to strings before concatenating them:

3 . 2.74 // gives the string 32.74

You can use a string anywhere PHP expects a number. The string is presumed to start with an integer or floating-point number. If no number is found at the start of the string, the numeric value of that string is 0. If the string contains a period (.) or upper- or lowercase e, evaluating it numerically produces a floating-point number. For example:

"9 Lives" - 1; // 8 (int)
"3.14 Pies" * 2; // 6.28 (float)
"9. Lives" - 1; // 8 (float / double)
"1E3 Points of Light" + 1; // 1001 (float)

Arithmetic Operators

The arithmetic operators are operators you’ll recognize from everyday use. Most of the arithmetic operators are binary; however, the arithmetic negation and arithmetic assertion operators are unary. These operators require numeric values, and nonnumeric values are converted into numeric values by the rules described in the section “Casting Operators”. The arithmetic operators are:

Addition (+)
The result of the addition operator is the sum of the two operands.
Subtraction ()
The result of the subtraction operator is the difference between the two operands—that is, the value of the second operand subtracted from the first.
Multiplication (*)
The result of the multiplication operator is the product of the two operands. For example, 3 * 4 is 12.
Division (/)
The result of the division operator is the quotient of the two operands. Dividing two integers can give an integer (e.g., 4 / 2) or a floating-point result (e.g., 1 / 2).
Modulus (%)
The modulus operator converts both operands to integers and returns the remainder of the division of the first operand by the second operand. For example, 10 % 6 gives a remainder of 4.
Arithmetic negation ()
The arithmetic negation operator returns the operand multiplied by −1, effectively changing its sign. For example, −(3 − 4) evaluates to 1. Arithmetic negation is different from the subtraction operator, even though they both are written as a minus sign. Arithmetic negation is always unary and before the operand. Subtraction is binary and between its operands.
Arithmetic assertion (+)
The arithmetic assertion operator returns the operand multiplied by +1, which has no effect. It is used only as a visual cue to indicate the sign of a value. For example, +(3 − 4) evaluates to −1, just as (3 − 4) does.
Exponentiation (**)
The exponentiation operator returns the result of raising $var1 to the power of $var2.
$var1 = 5;
$var2 = 3;
echo $var1 ** $var2; // outputs 125

String Concatenation Operator

Manipulating strings is such a core part of PHP applications that PHP has a separate string concatenation operator (.). The concatenation operator appends the righthand operand to the lefthand operand and returns the resulting string. Operands are first converted to strings, if necessary. For example:

$n = 5;
$s = 'There were ' . $n . ' ducks.';
// $s is 'There were 5 ducks'

The concatenation operator is highly efficient, because so much of PHP boils down to string concatenation.

Auto-increment and Auto-decrement Operators

In programming, one of the most common operations is to increase or decrease the value of a variable by one. The unary auto-increment (++) and auto-decrement (−−) operators provide shortcuts for these common operations. These operators are unique in that they work only on variables; the operators change their operands’ values and return a value.

There are two ways to use auto-increment or auto-decrement in expressions. If you put the operator in front of the operand, it returns the new value of the operand (incremented or decremented). If you put the operator after the operand, it returns the original value of the operand (before the increment or decrement). Table 2-5 lists the different operations.

Table 2-5. Auto-increment and auto-decrement operations
Operator Name Value returned Effect on $var
$var++ Post-increment $var Incremented
++$var Pre-increment $var + 1 Incremented
$var−− Post-decrement $var Decremented
−−$var Pre-decrement $var − 1 Decremented

These operators can be applied to strings as well as numbers. Incrementing an alphabetic character turns it into the next letter in the alphabet. As illustrated in Table 2-6, incrementing "z" or "Z" wraps it back to "a" or "A" and increments the previous character by one (or inserts a new "a" or "A" if at the first character of the string), as though the characters were in a base-26 number system.

Table 2-6. Auto-increment with letters
Incrementing this Gives this
"a" "b"
"z" "aa"
"spaz" "spba"
"K9" "L0"
"42" "43"

Comparison Operators

As their name suggests, comparison operators compare operands. The result is always either true, if the comparison is truthful, and false otherwise.

Operands to the comparison operators can be both numeric, both string, or one numeric and one string. The operators check for truthfulness in slightly different ways based on the types and values of the operands, either using strictly numeric comparisons or using lexicographic (textual) comparisons. Table 2-7 outlines when each type of check is used.

Table 2-7. Type of comparison performed by the comparison operators
First operand Second operand Comparison
Number Number Numeric
String that is entirely numeric String that is entirely numeric Numeric
String that is entirely numeric Number Numeric
String that is entirely numeric String that is not entirely numeric Lexicographic
String that is not entirely numeric Number Numeric
String that is not entirely numeric String that is not entirely numeric Lexicographic

One important thing to note is that two numeric strings are compared as if they were numbers. If you have two strings that consist entirely of numeric characters and you need to compare them lexicographically, use the strcmp() function.

The comparison operators are:

Equality (==)
If both operands are equal, this operator returns true; otherwise, it returns false.
Identity (===)
If both operands are equal and are of the same type, this operator returns true; otherwise, it returns false. Note that this operator does not do implicit type casting. This operator is useful when you don’t know if the values you’re comparing are of the same type. Simple comparison may involve value conversion. For instance, the strings "0.0" and "0" are not equal. The == operator says they are, but === says they are not.
Inequality (!= or <>)
If the operands are not equal, this operator returns true; otherwise, it returns false.
Not identical (!==)
If the operands are not equal, or they are not of the same type, this operator returns true; otherwise, it returns false.
Greater than (>)
If the lefthand operand is greater than the righthand operand, this operator returns true; otherwise, it returns false.
Greater than or equal to (>=)
If the lefthand operand is greater than or equal to the righthand operand, this operator returns true; otherwise, it returns false.
Less than (<)
If the lefthand operand is less than the righthand operand, this operator returns true; otherwise, it returns false.
Less than or equal to (<=)
If the lefthand operand is less than or equal to the righthand operand, this operator returns true; otherwise, it returns false.
Spaceship (<=>), aka “Darth Vadar’s TIE Fighter”

When the lefthand and righthand operands are equal, this operator returns 0; when the lefthand operand is less than the righthand, it returns -1; and when the lefthand operand is greater than the righthand, it returns 1.

$var1 = 5;
$var2 = 65;

echo $var1 <=> $var2 ; // outputs -1
echo $var2 <=> $var1 ; // outputs 1
Null coalescing operator (??)

This operator evaluates to the righthand operand if the lefthand operand is NULL; otherwise, it evaluates to the lefthand operand.

$var1 = null;
$var2 = 31;

echo $var1 ?? $var2 ; //outputs 31

Bitwise Operators

The bitwise operators act on the binary representation of their operands. Each operand is first turned into a binary representation of the value, as described in the bitwise negation operator entry in the following list. All the bitwise operators work on numbers as well as strings, but they vary in their treatment of string operands of different lengths. The bitwise operators are:

Bitwise negation (~)
The bitwise negation operator changes 1s to 0s and 0s to 1s in the binary representations of the operands. Floating-point values are converted to integers before the operation takes place. If the operand is a string, the resulting value is a string the same length as the original, with each character in the string negated.
Bitwise AND (&)

The bitwise AND operator compares each corresponding bit in the binary representations of the operands. If both bits are 1, the corresponding bit in the result is 1; otherwise, the corresponding bit is 0. For example, 0755 & 0671 is 0651. This is a little easier to understand if we look at the binary representation. Octal 0755 is binary 111101101, and octal 0671 is binary 110111001. We can then easily see which bits are in both numbers and visually come up with the answer:

 111101101
& 110111001
 ---------
 110101001
The binary number 110101001 is octal 0651.2 You can use the PHP functions bindec(), decbin(), octdec(), and decoct() to convert numbers back and forth when you are trying to understand binary arithmetic.
If both operands are strings, the operator returns a string in which each character is the result of a bitwise AND operation between the two corresponding characters in the operands. The resulting string is the length of the shorter of the two operands; trailing extra characters in the longer string are ignored. For example, "wolf" & "cat" is "cad".
Bitwise OR (|)
The bitwise OR operator compares each corresponding bit in the binary representations of the operands. If both bits are 0, the resulting bit is 0; otherwise, the resulting bit is 1. For example, 0755 | 020 is 0775.
If both operands are strings, the operator returns a string in which each character is the result of a bitwise OR operation between the two corresponding characters in the operands. The resulting string is the length of the longer of the two operands, and the shorter string is padded at the end with binary 0s. For example, "pussy" | "cat" is "suwsy".
Bitwise XOR (^)
The bitwise XOR operator compares each corresponding bit in the binary representation of the operands. If either of the bits in the pair, but not both, is 1, the resulting bit is 1; otherwise, the resulting bit is 0. For example, 0755 ^ 023 is 776.
If both operands are strings, this operator returns a string in which each character is the result of a bitwise XOR operation between the two corresponding characters in the operands. If the two strings are different lengths, the resulting string is the length of the shorter operand, and extra trailing characters in the longer string are ignored. For example, "big drink" ^ "AA" is "#(".
Left shift (<<)
The left-shift operator shifts the bits in the binary representation of the lefthand operand left by the number of places given in the righthand operand. Both operands will be converted to integers if they aren’t already. Shifting a binary number to the left inserts a 0 as the rightmost bit of the number and moves all other bits to the left one place. For example, 3 << 1 (or binary 11 shifted one place left) results in 6 (binary 110).
Note that each place to the left that a number is shifted results in a doubling of the number. The result of left shifting is multiplying the lefthand operand by 2 to the power of the righthand operand.
Right shift (>>)
The right-shift operator shifts the bits in the binary representation of the lefthand operand right by the number of places given in the righthand operand. Both operands will be converted to integers if they aren’t already. Shifting a positive binary number to the right inserts a 0 as the leftmost bit of the number and moves all other bits to the right one place. Shifting a negative binary number to the right inserts a 1 as the leftmost bit of the number and moves all other bits to the right one place. The rightmost bit is discarded. For example, 13 >> 1 (or binary 1101) shifted one bit to the right results in 6 (binary 110).

Logical Operators

Logical operators provide ways for you to build complex logical expressions. Logical operators treat their operands as Boolean values and return a Boolean value. There are both punctuation and English versions of the operators (|| and or are the same operator). The logical operators are:

Logical AND (&&, and)

The result of the logical AND operation is true if and only if both operands are true; otherwise, it is false. If the value of the first operand is false, the logical AND operator knows that the resulting value must also be false, so the righthand operand is never evaluated. This process is called short-circuiting, and a common PHP idiom uses it to ensure that a piece of code is evaluated only if something is true. For example, you might connect to a database only if some flag is not false:

$result = $flag and mysql_connect();
The && and and operators differ only in their precedence: && comes before and.
Logical OR (||, or)

The result of the logical OR operation is true if either operand is true; otherwise, the result is false. Like the logical AND operator, the logical OR operator is short-circuited. If the lefthand operator is true, the result of the operator must be true, so the righthand operator is never evaluated. A common PHP idiom uses this to trigger an error condition if something goes wrong. For example:

$result = fopen($filename) or exit();
The || and or operators differ only in their precedence.
Logical XOR (xor)
The result of the logical XOR operation is true if either operand, but not both, is true; otherwise, it is false.
Logical negation (!)
The logical negation operator returns the Boolean value true if the operand evaluates to false, and false if the operand evaluates to true.

Casting Operators

Although PHP is a weakly typed language, there are occasions when it’s useful to consider a value as a specific type. The casting operators, (int), (float), (string), (bool), (array), (object), and (unset), allow you to force a value into a particular type. To use a casting operator, put the operator to the left of the operand. Table 2-8 lists the casting operators, synonymous operators, and the type to which the operator changes the value.

Table 2-8. PHP casting operators
Operator Synonymous operators Changes type to
(int) (integer) Integer
(bool) (boolean) Boolean
(float) (double), (real) Floating point
(string)   String
(array)   Array
(object)   Object
(unset)   NULL

Casting affects the way other operators interpret a value rather than changing the value in a variable. For example, the code:

$a = "5";
$b = (int) $a;

assigns $b the integer value of $a; $a remains the string "5". To cast the value of the variable itself, you must assign the result of a cast back to the variable:

$a = "5";
$a = (int) $a; // now $a holds an integer

Not every cast is useful. Casting an array to a numeric type gives 1 (if the array is empty, it gives 0), and casting an array to a string gives "Array" (seeing this in your output is a sure sign that you’ve printed a variable that contains an array).

Casting an object to an array builds an array of the properties, thus mapping property names to values:

class Person
{
 var $name = "Fred";
 var $age = 35;
}

$o = new Person;
$a = (array) $o;

print_r($a);
Array ( [name] => Fred [age] => 35)

You can cast an array to an object to build an object whose properties correspond to the array’s keys and values. For example:

$a = array('name' => "Fred", 'age' => 35, 'wife' => "Wilma");
$o = (object) $a;
echo $o->name;
Fred

Keys that are not valid identifiers are invalid property names and are inaccessible when an array is cast to an object, but are restored when the object is cast back to an array.

Assignment Operators

Assignment operators store or update values in variables. The auto-increment and auto-decrement operators we saw earlier are highly specialized assignment operators—here we see the more general forms. The basic assignment operator is =, but we’ll also see combinations of assignment and binary operations, such as += and &=.

Assignment

The basic assignment operator (=) assigns a value to a variable. The lefthand operand is always a variable. The righthand operand can be any expression—any simple literal, variable, or complex expression. The righthand operand’s value is stored in the variable named by the lefthand operand.

Because all operators are required to return a value, the assignment operator returns the value assigned to the variable. For example, the expression $a = 5 not only assigns 5 to $a, but also behaves as the value 5 if used in a larger expression. Consider the following expressions:

$a = 5;
$b = 10;
$c = ($a = $b);

The expression $a = $b is evaluated first, because of the parentheses. Now, both $a and $b have the same value, 10. Finally, $c is assigned the result of the expression $a = $b, which is the value assigned to the lefthand operand (in this case, $a). When the full expression is done evaluating, all three variables contain the same value: 10.

Assignment with operation

In addition to the basic assignment operator, there are several assignment operators that are convenient shorthand. These operators consist of a binary operator followed directly by an equals sign, and their effect is the same as performing the operation with the full operands, then assigning the resulting value to the lefthand operand. These assignment operators are:

Plus-equals (+=)
Adds the righthand operand to the value of the lefthand operand, then assigns the result to the lefthand operand. $a += 5 is the same as $a = $a + 5.
Minus-equals (−=)
Subtracts the righthand operand from the value of the lefthand operand, then assigns the result to the lefthand operand.
Divide-equals (/=)
Divides the value of the lefthand operand by the righthand operand, then assigns the result to the lefthand operand.
Multiply-equals (*=)
Multiplies the righthand operand by the value of the lefthand operand, then assigns the result to the lefthand operand.
Modulus-equals (%=)
Performs the modulus operation on the value of the lefthand operand and the righthand operand, then assigns the result to the lefthand operand.
Bitwise-XOR-equals (^=)
Performs a bitwise XOR on the lefthand and righthand operands, then assigns the result to the lefthand operand.
Bitwise-AND-equals (&=)
Performs a bitwise AND on the value of the lefthand operand and the righthand operand, then assigns the result to the lefthand operand.
Bitwise-OR-equals (|=)
Performs a bitwise OR on the value of the lefthand operand and the righthand operand, then assigns the result to the lefthand operand.
Concatenate-equals (.=)
Concatenates the righthand operand to the value of the lefthand operand, then assigns the result to the lefthand operand.

Miscellaneous Operators

The remaining PHP operators are for error suppression, executing an external command, and selecting values:

Error suppression (@)
Some operators or functions can generate error messages. The error suppression operator, discussed in full in Chapter 17, is used to prevent these messages from being created.
Execution (`...`)

The backtick operator executes the string contained between the backticks as a shell command and returns the output. For example:

$listing = `ls -ls /tmp`;
echo $listing;
Conditional (? :)
The conditional operator is, depending on the code you look at, either the most overused or most underused operator. It is the only ternary (three-operand) operator and is therefore sometimes just called the ternary operator.

The conditional operator evaluates the expression before the ?. If the expression is true, the operator returns the value of the expression between the ? and :; otherwise, the operator returns the value of the expression after the :. For instance:

<a href="<? echo $url; ?>"><? echo $linktext ? $linktext : $url; ?></a>
If text for the link $url is present in the variable $linktext, it is used as the text for the link; otherwise, the URL itself is displayed.
Type (instanceof)

The instanceof operator tests whether a variable is an instantiated object of a given class or implements an interface (see Chapter 6 for more information on objects and interfaces):

$a = new Foo;
$isAFoo = $a instanceof Foo; // true
$isABar = $a instanceof Bar; // false

Flow-Control Statements

PHP supports a number of traditional programming constructs for controlling the flow of execution of a program.

Conditional statements, such as if/else and switch, allow a program to execute different pieces of code, or none at all, depending on some condition. Loops, such as while and for, support the repeated execution of particular segments of code.

if

The if statement checks the truthfulness of an expression and, if the expression is true, evaluates a statement. An if statement looks like:

if (expression)statement

To specify an alternative statement to execute when the expression is false, use the else keyword:

if (expression)
 statement
else statement

For example:

if ($user_validated)
 echo "Welcome!";
else
 echo "Access Forbidden!";

To include more than one statement within an if statement, use a block—a set of statements enclosed by curly braces:

if ($user_validated) {
 echo "Welcome!";
 $greeted = 1;
}
else {
 echo "Access Forbidden!";
 exit;
}

PHP provides another syntax for blocks in tests and loops. Instead of enclosing the block of statements in curly braces, end the if line with a colon (:) and use a specific keyword to end the block (endif, in this case). For example:

if ($user_validated):
 echo "Welcome!";
 $greeted = 1;
else:
 echo "Access Forbidden!";
 exit;
endif;

Other statements described in this chapter also have similar alternate syntax styles (and ending keywords); they can be useful if you have large blocks of HTML inside your statements. For example:

<?php if ($user_validated) : ?>
 <table>
 <tr>
 <td>First Name:</td><td>Sophia</td>
 </tr>
 <tr>
 <td>Last Name:</td><td>Lee</td>
 </tr>
 </table>
<?php else: ?>
 Please log in.
<?php endif ?>

Because if is a statement, you can chain (embed) more than one. This is also a good example of how the blocks can be used to help keep things organized:

if ($good) {
 print("Dandy!");
}
else {
 if ($error) {
 print("Oh, no!");
 }
 else {
 print("I'm ambivalent...");
 }
}

Such chains of if statements are common enough that PHP provides an easier syntax: the elseif statement. For example, the previous code can be rewritten as:

if ($good) {
 print("Dandy!");
}
elseif ($error) {
 print("Oh, no!");
}
else {
 print("I'm ambivalent...");
}

The ternary conditional operator (? :) can be used to shorten simple true/false tests. Take a common situation, such as checking to see if a given variable is true and printing something if it is. With a normal if/else statement, it looks like this:

<td><?php if($active) { echo "yes"; } else { echo "no"; } ?></td>

With the ternary conditional operator, it looks like this:

<td><?php echo $active ? "yes" : "no"; ?></td>

Compare the syntax of the two:

if (expression) { true_statement } else { false_statement }
 (expression) ? true_expression : false_expression

The main difference here is that the conditional operator is not a statement at all. This means that it is used on expressions, and the result of a complete ternary expression is itself an expression. In the previous example, the echo statement is inside the if condition, while when used with the ternary operator, it precedes the expression.

switch

The value of a single variable may determine one of a number of different choices (e.g., the variable holds the username and you want to do something different for each user). The switch statement is designed for just this situation.

A switch statement is given an expression and compares its value to all cases in the switch; all statements in a matching case are executed, up to the first break keyword it finds. If none match, and a default is given, all statements following the default keyword are executed, up to the first break keyword encountered.

For example, suppose you have the following:

if ($name == 'ktatroe') {
 // do something
}
else if ($name == 'dawn') {
 // do something
}
else if ($name == 'petermac') {
 // do something
}
else if ($name == 'bobk') {
 // do something
}

You can replace that statement with the following switch statement:

switch($name) {
 case 'ktatroe':
 // do something
 break;
 case 'dawn':
 // do something
 break;
 case 'petermac':
 // do something
 break;
 case 'bobk':
 // do something
 break;
}

The alternative syntax for this is:

switch($name):
 case 'ktatroe':
 // do something
 break;
 case 'dawn':
 // do something
 break;
 case 'petermac':
 // do something
 break;
 case 'bobk':
 // do something
 break;
endswitch;

Because statements are executed from the matching case label to the next break keyword, you can combine several cases in a fall-through. In the following example, “yes” is printed when $name is equal to sylvie or bruno:

switch ($name) {
 case 'sylvie': // fall-through
 case 'bruno':
 print("yes");
 break;
 default:
 print("no");
 break;
}

Commenting the fact that you are using a fall-through case in a switch is a good idea, so someone doesn’t come along at some point and add a break thinking you had forgotten it.

You can specify an optional number of levels for the break keyword to break out of. In this way, a break statement can break out of several levels of nested switch statements. An example of using break in this manner is shown in the next section.

while

The simplest form of loop is the while statement:

while (expression)statement

If the expression evaluates to true, the statement is executed and then the expression is re-evaluated (if it is still true, the body of the loop is executed again, and so on). The loop exits when the expression is no longer true (i.e., evaluates to false).

As an example, here’s some code that adds the whole numbers from 1 to 10:

$total = 0;
$i = 1;

while ($i <= 10) {
 $total += $i;
 $i++;
}

The alternative syntax for while has this structure:

while (expr):
 statement;
 more statements ;
endwhile;

For example:

$total = 0;
$i = 1;

while ($i <= 10):
 $total += $i;
 $i++;
endwhile;

You can prematurely exit a loop with the break keyword. In the following code, $i never reaches a value of 6, because the loop is stopped once it reaches 5:

$total = 0;
$i = 1;

while ($i <= 10) {
 if ($i == 5) {
 break; // breaks out of the loop
 }

 $total += $i;
 $i++;
}

Optionally, you can put a number after the break keyword indicating how many levels of loop structures to break out of. In this way, a statement buried deep in nested loops can break out of the outermost loop. For example:

$i = 0;
$j = 0;

while ($i < 10) {
 while ($j < 10) {
 if ($j == 5) {
 break 2; // breaks out of two while loops
 }

 $j++;
 }

 $i++;
}

echo "{$i}, {$j}";
0, 5

The continue statement skips ahead to the next test of the loop condition. As with the break keyword, you can continue through an optional number of levels of loop structure:

while ($i < 10) {
 $i++;

 while ($j < 10) {
 if ($j == 5) {
 continue 2; // continues through two levels
 }

 $j++;
 }
}

In this code, $j never has a value above 5, but $i goes through all values from 0 to 9.

PHP also supports a do/while loop, which takes the following form:

do
 statement
while (expression)

Use a do/while loop to ensure that the loop body is executed at least once (the first time):

$total = 0;
$i = 1;

do {
 $total += $i++;
} while ($i <= 10);

You can use break and continue statements in a do/while statement just as in a normal while statement.

The do/while statement is sometimes used to break out of a block of code when an error condition occurs. For example:

do {
 // do some stuff

 if ($errorCondition) {
 break;
 }

 // do some other stuff
} while (false);

Because the condition for the loop is false, the loop is executed only once, regardless of what happens inside the loop. However, if an error occurs, the code after the break is not evaluated.

for

The for statement is similar to the while statement, except it adds counter initialization and counter manipulation expressions, and is often shorter and easier to read than the equivalent while loop.

Here’s a while loop that counts from 0 to 9, printing each number:

$counter = 0;

while ($counter < 10) {
 echo "Counter is {$counter} <br/>";
 $counter++;
}

Here’s the corresponding, more concise for loop:

for ($counter = 0; $counter < 10; $counter++) {
 echo "Counter is $counter <br/>";
}

The structure of a for statement is:

for (start; condition; increment) { statement(s); }

The expression start is evaluated once, at the beginning of the for statement. Each time through the loop, the expression condition is tested. If it is true, the body of the loop is executed; if it is false, the loop ends. The expression increment is evaluated after the loop body runs.

The alternative syntax of a for statement is:

for (expr1; expr2; expr3):
 statement;
 ...;
endfor;

This program adds the numbers from 1 to 10 using a for loop:

$total = 0;

for ($i= 1; $i <= 10; $i++) {
 $total += $i;
}

Here’s the same loop using the alternate syntax:

$total = 0;

for ($i = 1; $i <= 10; $i++):
 $total += $i;
endfor;

You can specify multiple expressions for any of the expressions in a for statement by separating the expressions with commas. For example:

$total = 0;

for ($i = 0, $j = 1; $i <= 10; $i++, $j *= 2) {
 $total += $j;
}

You can also leave an expression empty, signaling that nothing should be done for that phase. In the most degenerate form, the for statement becomes an infinite loop. You probably don’t want to run this example, as it never stops printing:

for (;;) {
 echo "Can't stop me!<br />";
}

In for loops, as in while loops, you can use the break and continue keywords to end the loop or the current iteration.

foreach

The foreach statement allows you to iterate over elements in an array. The two forms of the foreach statement are further discussed in Chapter 5, where we talk in more depth about arrays. To loop over an array, accessing the value at each key, use:

foreach ($array as $current) {
 // ...
}

The alternate syntax is:

foreach ($array as $current):
 // ...
endforeach;

To loop over an array, accessing both key and value, use:

foreach ($array as $key => $value) {
 // ...
}

The alternate syntax is:

foreach ($array as $key => $value):
 // ...
endforeach;

try...catch

The try...catch construct is not so much a flow-control structure as it is a more graceful way to handle system errors. For example, if you want to ensure that your web application has a valid connection to a database before continuing, you could write code like this:

try {
 $dbhandle = new PDO('mysql:host=localhost; dbname=library', $username, $pwd);
 doDB_Work($dbhandle); // call function on gaining a connection
 $dbhandle = null; // release handle when done
}
catch (PDOException $error) {
 print "Error!: " . $error->getMessage() . "<br/>";
 die();
}

Here the connection is attempted with the try portion of the construct and if there are any errors with it, the flow of the code automatically falls into the catch portion, where the PDOException class is instantiated into the $error variable. It can then be displayed on the screen and the code can “gracefully” fail, rather than making an abrupt end. You can even redirect to try connecting to an alternate database, or respond to the error any other way you wish within the catch portion.

Note

See Chapter 9 for more examples of try...catch in relation to PDO (PHP Data Objects) and transaction processing.

declare

The declare statement allows you to specify execution directives for a block of code. The structure of a declare statement is:

declare (directive)statement

Currently, there are only three declare forms: the ticks, encoding, and strict_types directives. You can use the ticks directive to specify how frequently (measured roughly in number of code statements) a tick function is registered when register_tick_function() is called. For example:

register_tick_function("someFunction");

declare(ticks = 3) {
 for($i = 0; $i < 10; $i++) {
 // do something
 }
}

In this code, someFunction() is called after every third statement within the block is executed.

You can use the encoding directive to specify a PHP script’s output encoding. For example:

declare(encoding = "UTF-8");

This form of the declare statement is ignored unless you compile PHP with the --enable-zend-multibyte option.

Finally, you can use the strict_types directive to enforce the use of strict data types when defining and using variables.

exit and return

As soon as it is reached, the exit statement ends the script’s execution. The return statement returns from a function or, at the top level of the program, from the script.

The exit statement takes an optional value. If this is a number, it is the exit status of the process. If it is a string, the value is printed before the process terminates. The function die() is an alias for this form of the exit statement:

$db = mysql_connect("localhost", $USERNAME, $PASSWORD);

if (!$db) {
 die("Could not connect to database");
}

This is more commonly written as:

$db = mysql_connect("localhost", $USERNAME, $PASSWORD)
 or die("Could not connect to database");

See Chapter 3 for more information on using the return statement in functions.

goto

The goto statement allows execution to “jump” to another place in the program. You specify execution points by adding a label, which is an identifier followed by a colon (:). You then jump to the label from another location in the script via the goto statement:

for ($i = 0; $i < $count; $i++) {
 // oops, found an error
 if ($error) {
 goto cleanup;
 }
}

cleanup:
// do some cleanup

You can only goto a label within the same scope as the goto statement itself, and you can’t jump into a loop or switch. Generally, anywhere you might use a goto (or multilevel break statement, for that matter), you can rewrite the code to be cleaner without it.

Including Code

PHP provides two constructs to load code and HTML from another module: require and include. Both load a file as the PHP script runs, work in conditionals and loops, and complain if the file being loaded cannot be found. Files are located by an included file path as part of the directive in the use of the function, or based on the setting of include_path in the php.ini file. The include_path can be overridden by the set_include_path() function. If all these avenues fail, PHP’s last attempt is to try to find the file in the same directory as the calling script. The main difference is that attempting to require a nonexistent file is a fatal error, while attempting to include such a file produces a warning but does not stop script execution.

A common use of include is to separate page-specific content from general site design. Common elements such as headers and footers go in separate HTML files, and each page then looks like:

<?php include "header.html"; ?>
content
<?php include "footer.html"; ?>

We use include because it allows PHP to continue to process the page even if there’s an error in the site design file(s). The require construct is less forgiving and is more suited to loading code libraries, where the page cannot be displayed if the libraries do not load. For example:

require "codelib.php";
mysub(); // defined in codelib.php

A marginally more efficient way to handle headers and footers is to load a single file and then call functions to generate the standardized site elements:

<?php require "design.php";
header(); ?>
content
<?php footer();

If PHP cannot parse some part of a file added by include or require, a warning is printed and execution continues. You can silence the warning by prepending the call with the silence operator (@)—for example, @include.

If the allow_url_fopen option is enabled through PHP’s configuration file, php.ini, you can include files from a remote site by providing a URL instead of a simple local path:

include "http://www.example.com/codelib.php";

If the filename begins with http://, https://, or ftp://, the file is retrieved from a remote site and loaded.

Files included with include and require can be arbitrarily named. Common extensions are .php, .php5, and .html.

Note

Note that remotely fetching a file that ends in .php from a web server that has PHP enabled fetches the output of that PHP script—it executes the PHP code in that file.

If a program uses include or require to include the same file twice (mistakenly done in a loop, for example), the file is loaded and the code is run, or the HTML is printed twice. This can result in errors about the redefinition of functions, or multiple copies of headers or HTML being sent. To prevent these errors from occurring, use the include_once and require_once constructs. They behave the same as include and require the first time a file is loaded, but quietly ignore subsequent attempts to load the same file. For example, many page elements, each stored in separate files, need to know the current user’s preferences. The element libraries should load the user preferences library with require_once. The page designer can then include a page element without worrying about whether the user preference code has already been loaded.

Code in an included file is imported at the scope that is in effect where the include statement is found, so the included code can see and alter your code’s variables. This can be useful—for instance, a user-tracking library might store the current user’s name in the global $user variable:

// main page
include "userprefs.php";
echo "Hello, {$user}.";

The ability of libraries to see and change your variables can also be a problem. You have to know every global variable used by a library to ensure that you don’t accidentally try to use one of them for your own purposes, thereby overwriting the library’s value and disrupting how it works.

If the include or require construct is in a function, the variables in the included file become function-scope variables for that function.

Because include and require are keywords, not real statements, you must always enclose them in curly braces in conditional and loop statements:

for ($i = 0; $i < 10; $i++) {
 include "repeated_element.html";
}

Use the get_included_files() function to learn which files your script has included or required. It returns an array containing the full system path filenames of each included or required file. Files that did not parse are not included in this array.

Embedding PHP in Web Pages

Although it is possible to write and run standalone PHP programs, most PHP code is embedded in HTML or XML files. This is, after all, why it was created in the first place. Processing such documents involves replacing each chunk of PHP source code with the output it produces when executed.

Because a single file usually contains PHP and non-PHP source code, we need a way to identify the regions of PHP code to be executed. PHP provides four different ways to do this.

As you’ll see, the first, and preferred, method looks like XML. The second method looks like SGML. The third method is based on ASP tags. The fourth method uses the standard HTML <script> tag; this makes it easy to edit pages with enabled PHP using a regular HTML editor.

Standard (XML) Style

Because of the advent of the eXtensible Markup Language (XML) and the migration of HTML to an XML language (XHTML), the currently preferred technique for embedding PHP uses XML-compliant tags to denote PHP instructions.

Coming up with tags to demark PHP commands in XML was easy, because XML allows the definition of new tags. To use this style, surround your PHP code with <?php and ?>. Everything between these markers is interpreted as PHP, and anything outside the markers is not. Although it is not necessary to include spaces between the markers and the enclosed text, doing so improves readability. For example, to get PHP to print “Hello, world,” you can insert the following line in a web page:

<?php echo "Hello, world"; ?>

The trailing semicolon on the statement is optional, because the end of the block also forces the end of the expression. Embedded in a complete HTML file, this looks like:

<!doctype html>
<html>
<head>
 <title>This is my first PHP program!</title>
</head>

<body>
<p>
 Look, ma! It's my first PHP program:<br />
 <?php echo "Hello, world"; ?><br />
 How cool is that?
</p>
</body>

</html>

Of course, this isn’t very exciting—we could have done it without PHP. The real value of PHP comes when we put dynamic information from sources such as databases and form values into the web page. That’s for a later chapter, though. Let’s get back to our “Hello, world” example. When a user visits this page and views its source, it looks like this:

<!doctype html>
<html>
<head>
 <title>This is my first PHP program!</title>
</head>

<body>
<p>
 Look, ma! It's my first PHP program:<br />
 Hello, world!<br />
 How cool is that?
</p>
</body>

</html>

Notice that there’s no trace of the PHP source code from the original file. The user sees only its output.

Also notice that we switched between PHP and non-PHP, all in the space of a single line. PHP instructions can be put anywhere in a file, even within valid HTML tags. For example:

<input type="text" name="first_name" value="<?php echo "Peter"; ?>" />

When PHP is done with this text, it will read:

<input type="text" name="first_name" value="Peter" />

The PHP code within the opening and closing markers does not have to be on the same line. If the closing marker of a PHP instruction is the last thing on a line, the line break following the closing tag is removed as well. Thus, we can replace the PHP instructions in the “Hello, world” example with:

<?php
echo "Hello, world"; ?>
<br />

with no change in the resulting HTML.

SGML Style

Another style of embedding PHP comes from SGML instruction processing tags. To use this method, simply enclose the PHP in <? and ?>. Here’s the “Hello, world” example again:

<? echo "Hello, world"; ?>

This style, known as short tags, is off by default. You can turn on support for short tags by building PHP with the --enable-short-tags option, or enable short_open_tag in the PHP configuration file. This is discouraged as it depends on the state of this setting; if you export your code to another platform, it may or may not work.

The short echo tag, <?= ... ?>, is available regardless of the availability of short tags.

Echoing Content Directly

Perhaps the single most common operation within a PHP application is displaying data to the user. In the context of a web application, this means inserting into the HTML document information that will become HTML when viewed by the user.

To simplify this operation, PHP provides a special version of the SGML tags that automatically take the value inside the tag and insert it into the HTML page. To use this feature, add an equals sign (=) to the opening tag. With this technique, we can rewrite our form example as:

<input type="text" name="first_name" value="<?= "Dawn"; ?>">

What’s Next

Now that you have the basics of the language under your belt—a foundational understanding of what variables are and how to name them, what data types are, and how code flow control works—we will move on to some finer details of the PHP language. Next we’ll cover three topics that are so important to PHP that they each have their own dedicated chapters: how to define functions (Chapter 3), manipulate strings (Chapter 4), and manage arrays (Chapter 5).

1 It is actually 3 if you are looking at the reference count from the C API, but for the purposes of this explanation and from a user-space perspective, it is easier to think of it as 2.

2 Here’s a tip: split the binary number into three groups—6 is binary 110, 5 is binary 101, and 1 is binary 001; thus, 0651 is 110101001.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset