Chapter 2 covered the basics of how to represent data in PHP programs. A program full of data is only half complete, though. The other piece of the puzzle is using that data to control how the program runs, taking actions such as:
All of these actions have something in common: they make decisions about whether a certain logical condition involving data is true or false. In the first action, the logical condition is “Is an administrative user logged in?” If the condition is true (yes, an administrative user is logged in), then a special menu is printed. The same kind of thing happens in the next example. If the condition “Is it after three o’clock?” is true, then a different page header is printed. Likewise, if “Have new messages been posted since the user last logged in?” is true, then the user is notified.
When making decisions, the PHP engine boils down an expression
into true or false. “Understanding true and false” explains how the
engine decides which expressions and values are
true and which are false.
Those true and false values are
used by language constructs such as if() to
decide whether to run certain statements in a program. The ins and
outs of if() are detailed in “Making Decisions”. Use
if() and similar constructs any time the outcome
of a program depends on some changing conditions.
While true and false are the
cornerstones of decision making, usually you want to ask more
complicated questions, such as “Is this user at
least 21 years old?” or “Does this
user have a monthly subscription to the website or enough money in
his account to buy a daily pass?” “Building Complicated Decisions” explains PHP’s comparison and logical
operators. These help you express whatever kinds of decisions you need
to make in a program, such as seeing whether numbers or strings are
greater than or less than each other. You can also chain together
decisions into a larger decision that depends on its pieces.
Decision making is also used in programs when you want to repeatedly
execute certain statements, and you need a way to indicate when
the repetition should stop. Frequently, this is determined by a
simple counter, such as “repeat 10
times.” This is like asking the question
“Have I repeated 10 times yet?” If
so, then the program continues. If not, the action is repeated again.
Determining when to stop can be more complicated, too—for
example, “Show another math question to a student
until six questions have been answered correctly.” “Repeating Yourself” introduces PHP’s while() and for() constructs, which you can use to implement these kinds of loops.
Every expression in a PHP program has a truth value:
true or false. Sometimes that
truth value is important because you use it in a calculation, but
sometimes you ignore it. Understanding how expressions evaluate to
true or false is an important part of understanding PHP.
Most scalar values are true. All integers and
floating-point numbers (except for 0
and 0.0) are true. All strings are
true except for two: a string containing nothing
at all and a string containing only the character
0.
The special constants false and null also evaluate to
false. These six values are false. Everything else is
true.1
A variable equal to one of the false values, or a
function that returns one of those values, also evaluates to false. Every
other expression evaluates to true.
Figuring out the truth value of an expression has two steps. First,
figure out the actual value of the expression. Then, check whether
that value is true or false.
Some expressions have common-sense values. The value of a
mathematical expression is what you’d get by doing
the math with paper and pencil. For example, 7 * 6
equals 42. Since 42 is true,
the expression 7 * 6 is true.
The expression 5 - 6 + 1 equals
0. Since 0 is
false, the expression 5 - 6 + 1
is false.
The same is true with string concatenation. The value of an
expression that concatenates two strings is the new combined
string. The expression 'jacob' . '@example.com' equals the string
jacob@example.com, which is true.
The value of an
assignment operation is the value
being assigned. The expression $price = 5 evaluates to
5, since that’s what’s being assigned to $price.
Because assignment produces a result, you can chain assignment
operations together to assign the same value to multiple variables:
$price=$quantity=5;
This expression means “set $price
equal to the result of setting $quantity equal to
5.” When this expression is
evaluated, the integer 5 is assigned to the
variable $quantity. The result of that assignment
expression is 5, the value being assigned. Then,
that result (5) is assigned to the variable
$price. Both $price and
$quantity are set to 5.
With the if() construct, you can have statements in your program that
are only run if certain conditions are true. This
lets your program take different actions depending on the
circumstances. For example, you can check that a user has entered
valid information in a web form before letting her see sensitive
data.
The if() construct runs a block of code if its
test expression is true. This is demonstrated in
Example 3-1.
if($logged_in){"Welcome aboard, trusted user.";}
The if() construct finds the truth value of the
expression inside its parentheses (the test
expression). If the expression evaluates to
true, then the statements inside the
curly braces after the if() are run. If the expression isn’t
true, then the program continues with the
statements after the curly braces. In this case, the test expression
is just the variable $logged_in. If
$logged_in is true (or has a
value that evaluates to true, such as 5, -12.6, or
Grass Carp), then Welcome aboard, trusted user. is printed.
You can have as many statements as you want in the code block inside
the curly braces. However, you need to terminate each of them with a
semicolon. This is the same rule that applies to code outside an
if() statement. You don’t, however, need a semicolon
after the closing curly brace that encloses the code block. You also
don’t put a semicolon after the opening curly brace. Example 3-2 shows an if() clause that runs multiple statements when
its test expression is true.
"This is always printed.";if($logged_in){"Welcome aboard, trusted user.";'This is only printed if $logged_in is true.';}"This is also always printed.";
To run different statements when the if() test
expression is false, add an else clause
to your if() statement. This is shown in
Example 3-3.
if($logged_in){"Welcome aboard, trusted user.";}else{"Howdy, stranger.";}
In Example 3-3, the first print
statement is only executed when the if() test
expression (the variable $logged_in) is
true. The second print
statement, inside the else clause, is only run
when the test expression is false.
The if() and else constructs
are extended further with
the elseif() construct. You can pair one or more elseif() clauses with an if() to test multiple
conditions separately. Example 3-4 demonstrates
elseif().
if($logged_in){// This runs if $logged_in is true"Welcome aboard, trusted user.";}elseif($new_messages){// This runs if $logged_in is false but $new_messages is true"Dear stranger, there are new messages.";}elseif($emergency){// This runs if $logged_in and $new_messages are false// but $emergency is true"Stranger, there are no new messages, but there is an emergency.";}
If the test expression for the if() statement is
true, the PHP engine executes the statements
inside the code block after the if() and ignores
the elseif() clauses and their code blocks. If
the test expression for the if() statement is
false, then the engine moves on to the first
elseif() statement and applies the same logic. If
that test expression is true, then it runs the
code block for that elseif() statement. If it is
false, then the engine moves on to the next
elseif().
For a given set of if() and elseif() statements, at most one of the code blocks is run: the
code block of the first statement whose test expression is
true. If the test expression of the if() statement is true, none of the
elseif() code blocks are run, even if their test
expressions are true. Once one of the if() or elseif() test expressions is
true, the rest are ignored. If none of the test
expressions in the if() and elseif() statements are true, then none of the
code blocks are run.
You can use else with elseif()
to include a code block that runs if none of the if() or elseif() test expressions are
true. Example 3-5 adds an
else to the code in Example 3-4.
if($logged_in){// This runs if $logged_in is true"Welcome aboard, trusted user.";}elseif($new_messages){// This runs if $logged_in is false but $new_messages is true"Dear stranger, there are new messages.";}elseif($emergency){// This runs if $logged_in and $new_messages are false// but $emergency is true"Stranger, there are no new messages, but there is an emergency.";}else{// This runs if $logged_in, $new_messages, and// $emergency are all false"I don't know you, you have no messages, and there's no emergency.";}
All of the code blocks we’ve used so far have been surrounded by curly braces. Strictly speaking, you don’t need to put curly braces around code blocks that contain just one statement. If you leave them out, the code still executes correctly. However, reading the code can be confusing if you leave out the curly braces, so it’s always a good idea to include them. The PHP engine doesn’t care, but humans who read your programs (especially you, reviewing code a few months after you’ve originally written it) will appreciate the clarity that the curly braces provide.
The comparison and logical operators in PHP help you put together
more complicated expressions on which an if() construct can decide. These
operators let you compare values, negate values, and chain together
multiple expressions inside one if() statement.
The equal operator is == (two equals signs). It returns
true if the two values you test with it are
equal. The values can be variables or literals. Some uses of the
equal operator are shown in Example 3-6.
if($new_messages==10){"You have ten new messages.";}if($new_messages==$max_messages){"You have the maximum number of messages.";}if($dinner=='Braised Scallops'){"Yum! I love seafood.";}
The opposite of the equal operator is
!=. It returns true if the two
values that you test with it are not equal. See Example 3-7.
if($new_messages!=10){"You don't have ten new messages.";}if($dinner!='Braised Scallops'){"I guess we're out of scallops.";}
With the less-than operator
(<) and the greater-than operator
(>), you can compare amounts. Similar to
< and > are
<= (“less than or equal
to”) and >=
(“greater than or equal
to”). Example 3-8 shows how to use
these operators.
if($age>17){"You are old enough to download the movie.";}if($age>=65){"You are old enough for a discount.";}if($celsius_temp<=0){"Uh-oh, your pipes may freeze.";}if($kelvin_temp<20.3){"Your hydrogen is a liquid or a solid now.";}
As mentioned in “Numbers”, floating-point numbers are stored internally in such a way that they could be slightly different than their assigned values. For example, 50.0 could be stored internally as 50.00000002. To test whether two floating-point numbers are equal, check whether the two numbers differ by less than some acceptably small threshold instead of using the equal operator. For example, if you are comparing currency amounts, then an acceptable threshold could be 0.00001. Example 3-9 demonstrates how to compare two floating-point numbers.
if(abs($price_1-$price_2)<0.00001){'$price_1 and $price_2 are equal.';}else{'$price_1 and $price_2 are not equal.';}
The abs() function used in Example 3-9 returns the absolute value of its argument. With abs(), the
comparison works properly whether $price_1 is
larger than $price_2 or
$price_2 is larger than
$price_1.
The less-than and greater-than operators (and their “or equal to” partners) can be used with numbers or strings. Generally, strings are compared as if they were being looked up in a dictionary. A string that appears earlier in the dictionary is “less than” a string that appears later in the dictionary. Some examples of this are shown in Example 3-10.
if($word<'baa'){"Your word isn't cookie.";}if($word>='zoo'){"Your word could be zoo or zymurgy, but not zone.";}
String comparison can produce unexpected results, however, if the strings contain only numbers or start with numbers. When the PHP engine sees strings like this, it converts them to numbers for the comparison. Example 3-11 shows this automatic conversion in action.
// These values are compared using dictionary orderif("x54321">"x5678"){'The string "x54321" is greater than the string "x5678".';}else{'The string "x54321" is not greater than the string "x5678".';}// These values are compared using numeric orderif("54321">"5678"){'The string "54321" is greater than the string "5678".';}else{'The string "54321" is not greater than the string "5678".';}// These values are compared using dictionary orderif('6 pack'<'55 card stud'){'The string "6 pack" is less than the string "55 card stud".';}else{'The string "6 pack" is not less than the string "55 card stud".';}// These values are compared using numeric orderif('6 pack'<55){'The string "6 pack" is less than the number 55.';}else{'The string "6 pack" is not less than the number 55.';}
The output of the four tests in Example 3-11 is:
The string "x54321" is not greater than the string "x5678". The string "54321" is greater than the string "5678". The string "6 pack" is not less than the string "55 card stud". The string "6 pack" is less than the number 55.
In the first test, because both of the strings start with a letter,
they are treated as regular strings and compared using dictionary
order. Their first two characters (x5) are the
same, but the third character of the first word
(4) is less than the third character of the second
word (6),2 so the greater-than comparison returns
false. In the second test, each string consists
entirely of numerals, so the strings are compared as numbers. The
number 54,321 is larger than the number 5,678, so the greater-than
comparison returns true. In the third test,
because both strings consist of numerals and other characters, they
are treated as strings and compared using dictionary order. The
numeral 6 comes after 5 in the engine’s
dictionary, so the less-than test returns false.
In the last test, the PHP engine converts the string 6
pack to the number 6, and then compares
it to the number 55 using numeric order. Since
6 is less than 55, the
less-than test returns true.
If you want to ensure that the PHP engine compares strings using
dictionary order without any converting to
numbers behind the scenes, use the built-in function strcmp(). It
always compares its arguments in dictionary order.
The strcmp() function takes two
strings as arguments. It returns a
positive number if the first string is greater than the second string
or a negative number if the first string is less than the first
string. “Greater than” and
“less than” for strcmp() are defined by dictionary order. The function returns 0 if the strings are equal.
The same comparisons from Example 3-11 are shown
using strcmp() in Example 3-12.
$x=strcmp("x54321","x5678");if($x>0){'The string "x54321" is greater than the string "x5678".';}elseif($x<0){'The string "x54321" is less than the string "x5678".';}$x=strcmp("54321","5678");if($x>0){'The string "54321" is greater than the string "5678".';}elseif($x<0){'The string "54321" is less than the string "5678".';}$x=strcmp('6 pack','55 card stud');if($x>0){'The string "6 pack" is greater than the string "55 card stud".';}elseif($x<0){'The string "6 pack" is less than the string "55 card stud".';}$x=strcmp('6 pack',55);if($x>0){'The string "6 pack" is greater than the number 55.';}elseif($x<0){'The string "6 pack" is less than the number 55.';}
The output from Example 3-12 is as follows:
The string "x54321" is less than the string "x5678". The string "54321" is less than the string "5678". The string "6 pack" is greater than the string "55 card stud". The string "6 pack" is greater than the number 55.
Using strcmp() and dictionary order produces
different results than Example 3-11 for the second
and fourth comparisons. In the second comparison, strcmp() computes that the string 54321 is less
than 5678 because the second characters of the
strings differ and 4 comes before
6. It doesn’t matter to
strcmp() that 5678 is shorter
than 54321 or that it is numerically smaller. In
dictionary order, 54321 comes before
5678. The fourth comparison turns out differently
because strcmp() doesn’t convert
6 pack to a number. Instead, it compares
6 pack and 55 as strings and
computes that 6 pack is bigger because its first
character, 6, comes later in the dictionary than
the first character of 55.
The spaceship operator (<=>) does comparison similar to strcmp(), but for any data type. It evaluates to a negative number when its lefthand operand is less than the righthand operand, a positive number when the righthand operand is bigger, and 0 when they are equal. Example 3-13 shows the spaceship operator at work.
// $a is a negative number since 1 is less than 12.7$a=1<=>12.7;// $b is a positive number since "c" comes after "b"$b="charlie"<=>"bob";// Comparing numeric strings works like < and >, not like strcmp()$x='6 pack'<=>'55 card stud';if($x>0){'The string "6 pack" is greater than the string "55 card stud".';}elseif($x<0){'The string "6 pack" is less than the string "55 card stud".';}// Comparing numeric strings works like < and >, not like strcmp()$x='6 pack'<=>55;if($x>0){'The string "6 pack" is greater than the number 55.';}elseif($x<0){'The string "6 pack" is less than the number 55.';}
The spaceship operator was introduced in PHP 7. If you’re using an older version of PHP, stick with the other comparison operators.
Example 3-13 prints:
The string "6 pack" is greater than the string "55 card stud". The string "6 pack" is less than the number 55.
The spaceship operator follows the same rules about string and number conversion as the other comparison operators. It converts “numerical” strings to numbers just like ==, <, and the others.
To negate a truth value, use !.
Putting ! before an expression is like testing to
see whether the expression equals
false. The two if() statements in Example 3-14 are equivalent.
// The entire test expression ($finished == false)// is true if $finished is falseif($finished==false){'Not done yet!';}// The entire test expression (! $finished)// is true if $finished is falseif(!$finished){'Not done yet!';}
You can use the negation operator with any value. If the value is
true, then the combination of it with the negation
operator is false. If the value is
false, then the combination of it with the
negation operator is true. Example 3-15 shows the negation operator at work with a
call to strcasecmp().
if(!strcasecmp($first_name,$last_name)){'$first_name and $last_name are equal.';}
In Example 3-15, the statement in the if() code block is executed only when the entire
test expression is
true. When the two strings provided to
strcasecmp() are equal (ignoring capitalization),
strcasecmp() returns 0, which is
false. The test expression is the negation
operator applied to this false value. The negation
of false is true. So, the
entire test expression is true when two equal
strings are given to strcasecmp().
With logical operators, you can
combine multiple expressions inside one if()
statement. The logical AND operator
(&&) tests whether
one expression and another are both true. The
logical OR operator
(||) tests whether either one expression or another (or both)
is true. These logical operators are used in Example 3-16.
if(($age>=13)&&($age<65)){"You are too old for a kid's discount and too young for the senior'sdiscount.";}if(($meal=='breakfast')||($dessert=='souffle')){"Time to eat some eggs.";}
The first test expression in Example 3-16 is
true when both of its subexpressions are
true—when $age is at
least 13 but not more than 65. The second test expression is
true when at least one of its subexpressions is
true: when $meal is
breakfast or $dessert is
souffle.
The admonition about operator precedence and parentheses from Chapter 2 holds true for logical operators in test expressions, too. To avoid ambiguity, surround each subexpression with parentheses inside a larger test expression.
When a computer program does something repeatedly,
it’s called looping. This
happens a lot—for example, when you want to retrieve a set of
rows from a database, print rows of an HTML table, or print elements
in an HTML <select> menu. The two looping constructs discussed in this
section are while() and for(). Their specifics differ, but each requires you to
specify the two essential attributes of any loop: what code to
execute repeatedly and when to stop. The code to execute is a code
block just like what goes inside the curly braces after an
if() construct. The condition for stopping the
loop is a logical expression just like an if()
construct’s test expression.
The while()
construct is like a repeating if(). You provide
an expression to while(), just like to
if(). If the expression is true, then a code
block is executed. Unlike if(), however,
while() checks the expression again after
executing the code block. If it’s still
true, then the code block is executed again (and
again, and again, as long as the expression is
true.) Once the expression is
false, program execution continues with the lines
after the code block. As you have probably guessed, your code block
should do something that changes the outcome of the test expression
so that the loop doesn’t go on forever.
Example 3-17 uses while() to
print an HTML form
<select> menu with 10 choices.
$i=1;'<select name="people">';while($i<=10){"<option>$i</option>\n";$i++;}'</select>';
Example 3-17 prints:
<selectname="people"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option><option>6</option><option>7</option><option>8</option><option>9</option><option>10</option></select>
Before the while() loop runs, the code sets
$i to 1 and prints the opening
<select> tag. The test expression compares
$i to 10. As long as
$i is less than or equal to 10, the two statements
in the code block are executed. The first prints an
<option> tag for the
<select> menu, and the second increments
$i. If you didn’t increment
$i inside the while() loop,
Example 3-17 would print out
<option>1</option> forever.
After the code block prints
<option>10</option>, the
$i++ line makes $i equal to 11.
Then the test expression ($i <= 10) is
evaluated. Since it’s not true
(11 is not less than or equal to 10), the program continues past the
while() loop’s code block and
prints the closing </select> tag.
The for()
construct also provides
a way for you to execute the same statements multiple times. Example 3-18 uses for() to print the same HTML form <select> menu as Example 3-17.
'<select name="people">';for($i=1;$i<=10;$i++){"<option>$i</option>\n";}'</select>';
Using for()
is a little more complicated than using
while(). Instead of one test expression in parentheses, there are
three expressions separated with semicolons: the initialization
expression, test expression, and iteration expression. Once
you get the hang of it, however, for() is a more
concise way to have a loop with easy-to-express initialization and
iteration conditions.
The first expression in Example 3-18, $i =
1, is the initialization
expression. It is evaluated once, when the loop starts.
This is where you put variable initializations or other setup code.
The second expression in Example 3-18, $i <= 10, is the test expression. It is evaluated once each time
through the loop, before the statements in the loop body. If
it’s true, then the loop body is
executed (print "<option>$i</option>";
in Example 3-18). The third expression in Example 3-18, $i++, is the iteration expression. It
is run after each time the loop body is executed. In Example 3-18, the sequence of statements goes like this:
$i = 1;$i <= 10 (true, $i is
1)print "<option>$i</option>";$i++;$i <= 10 (true, $i is
2)print "<option>$i</option>";$i++;$i)$i <= 10 (true, $i is
9)print "<option>$i</option>";$i++;$i <= 10 (true, $i is
10)print "<option>$i</option>";$i++;$i <= 10 (false, $i is
11)You can combine multiple expressions in the initialization expression
and the iteration expression of a for() loop by
separating each of the individual expressions with a comma. This is
usually done when you want to change more than one variable as the
loop progresses. Example 3-19 applies this to the variables $min and $max.
'<select name="doughnuts">';for($min=1,$max=10;$min<50;$min+=10,$max+=10){"<option>$min-$max</option>\n";}'</select>';
Each time through the loop, $min and
$max are each incremented by
10. Example 3-19
prints:
<selectname="doughnuts"><option>1 - 10</option><option>11 - 20</option><option>21 - 30</option><option>31 - 40</option><option>41 - 50</option></select>
This chapter covered:
true or falseif()if() with elseif() with elseif()if(),
elseif(), or else code block==) and not-equal
(!=) operators in test expressions=) and equality
comparison (==)<), greater-than
(>), less-than-or-equal-to
(<=), and greater-than-or-equal-to
(>=) operators in test expressionsabs()strcmp() or
strcasecmp()<=>)!) in test
expressions&& and
||) to build more complicated test expressionswhile()for()Without using a PHP program to evaluate them, determine whether each of these expressions is true or false:
100.00 - 100"zero""false"0 + "true"0.000"0.0"strcmp("false","False")0 <=> "0"Without running it through the PHP engine, figure out what this program prints:
$age=12;$shoe_size=13;if($age>$shoe_size){"Message 1.";}elseif(($shoe_size++)&&($age>20)){"Message 2.";}else{"Message 3.";}"Age:$age. Shoe Size:$shoe_size";
while() to print a table of Fahrenheit
and Celsius temperature equivalents from –50 degrees F to 50 degrees
F in 5-degree increments. On the Fahrenheit temperature scale, water
freezes at 32 degrees and boils at 212 degrees. On the Celsius scale,
water freezes at 0 degrees and boils at 100 degrees. So, to convert
from Fahrenheit to Celsius, you subtract 32 from the temperature,
multiply by 5, and divide by 9. To convert from Celsius to
Fahrenheit, you multiply by 9, divide by 5, and then add 32.for()
instead of while().