DekGenius.com
Previous Section  < Day Day Up >  Next Section

3.3 Building Complicated Decisions

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 equality operator is = =. It returns true if the two values you test with it are equal. The values can be variables or literals. Some uses of the equality operator are shown in Example 3-6.

Example 3-6. The equality operator
if ($new_messages == 10) {
    print "You have ten new messages.";
}

if ($new_messages == $max_messages) {
    print "You have the maximum number of messages.";
}

if ($dinner == 'Braised Scallops') {
    print "Yum! I love seafood.";
}

The opposite of the equality operator is !=. It returns true if the two values that you test with it are not equal. See Example 3-7.

Assignment Versus Comparison

Be careful not to use = when you mean = =. A single equals sign assigns a value and returns the value assigned. Two equals signs test for equality and return true if the values are equal. If you leave off the second equals sign, you usually get an if( ) test that is always true, as in the following:

if ($new_messages = 12) {
    print "It seems you now have twelve new messages.";
}

Instead of testing whether $new_messages equals 12, the code shown here sets $new_messages to 12. This assignment returns 12, the value being assigned. The if( ) test expression is always true, no matter what the value of $new_messages. Additionally, the value of $new_messages is overwritten. One way to avoid using = instead of = = is to put the variable on the right side of the comparison and the literal on the left side, as in the following:

if (12 == $new_messages) {
    print "You have twelve new messages.";
}

The test expression above may look a little funny, but it gives you some insurance if you accidentally use = instead of = =. With one equals sign, the test expression is 12 = $new_messages, which means "assign the value of $new_messages to 12." This doesn't make any sense: you can't change the value of 12. If the PHP interpreter sees this in your program, it reports a parse error and the program doesn't run. The parse error alerts you to the missing =. With the literal on the righthand side of the expression, the code is parseable by the interpreter, so it doesn't report an error.


Example 3-7. The not-equals operator
if ($new_messages != 10) {
    print "You don't have ten new messages.";
}

if ($dinner != 'Braised Scallops') {
    print "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.

Example 3-8. Less-than and greater-than
if ($age> 17) {
    print "You are old enough to download the movie.";
}
if ($age >= 65) {
    print "You are old enough for a discount.";
}
if ($celsius_temp <= 0) {
    print "Uh-oh, your pipes may freeze.";
}
if ($kelvin_temp < 20.3) {
    print "Your hydrogen is a liquid or a solid now.";
}

As mentioned in Section 2.2, floating-point numbers are stored internally in such a way that they could be slightly different than their assigned value. 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 equality operator. For example, if you are comparing currency amounts, then an acceptable threshold would be 0.00001. Example 3-9 demonstrates how to compare two floating point numbers.

Example 3-9. Comparing floating-point numbers
if(abs($price_1 - $price_2) < 0.00001) {
    print '$price_1 and $price_2 are equal.';
} else {
    print '$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 (and their "or equal to" partners) operators 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.

Example 3-10. Comparing strings
if ($word < 'baa') {
    print "Your word isn't cookie.";
}
if ($word>= 'zoo') {
    print "Your word could be zoo or zymurgy, but not zone.";
}

String comparison can produce unexpected results, however, if the strings contain numbers or start with numbers. When the PHP interpreter sees strings like this, it converts them to numbers for the comparison. Example 3-11 shows this automatic conversion in action.

Example 3-11. Comparing numbers and strings
// These values are compared using dictionary order
if ("x54321"> "x5678") {
    print 'The string "x54321" is greater than the string "x5678".';
} else {
    print 'The string "x54321" is not greater than the string "x5678".';
}

// These values are compared using numeric order
if ("54321" > "5678") {
    print 'The string "54321" is greater than the string "5678".';
} else {
    print 'The string "54321" is not greater than the string "5678".';
}

// These values are compared using dictionary order
if ('6 pack' < '55 card stud') {
    print 'The string "6 pack" is less than than the string "55 card stud".';
} else {
    print 'The string "6 pack" is not less than the string "55 card stud".';
}

// These values are compared using numeric order
if ('6 pack' < 55) {
    print 'The string "6 pack" is less than the number 55.';
} else {
    print '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 interpreter's dictionary, so the less-than test returns false. In the last test, the PHP interpreter 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.

[2] The "dictionary" that the PHP interpreter uses for comparing strings are the ASCII codes for characters. This puts numerals before letters, and orders the numerals from 0 to 9. It also puts uppercase letters before lowercase letters.

If you want to ensure that the PHP interpreter 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.

Example 3-12. Comparing strings with strcmp( )
$x = strcmp("x54321","x5678"); 
if ($x > 0) {
    print 'The string "x54321" is greater than the string "x5678".';
} elseif ($x < 0) {
    print 'The string "x54321" is less than the string "x5678".';
}

$x = strcmp("54321","5678");
if ($x > 0) {
    print 'The string "54321" is greater than the string "5678".';
} elseif ($x < 0) {
    print 'The string "54321" is less than the string "5678".';
}

$x = strcmp('6 pack','55 card stud');
if ($x > 0) {
    print 'The string "6 pack" is greater than than the string "55 card stud".';
} elseif ($x < 0) {
    print 'The string "6 pack" is less than the string "55 card stud".';
}

$x = strcmp('6 pack',55);
if ($x > 0) {
    print 'The string "6 pack" is greater than the number 55.';
} elseif ($x < 0) {
    print '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 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.

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-13 are equivalent.

Example 3-13. Using the negation operator
// The entire test expression ($finished == false) 
// is true if $finished is false 
if ($finished == false) {
    print 'Not done yet!';
}

// The entire test expression (! $finished)
// is true if $finished is false
if (! $finished) {
    print '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-14 shows the negation operator at work with a call to strcasecmp( ).

Example 3-14. Negation operator
if (! strcasecmp($first_name,$last_name)) {
    print '$first_name and $last_name are equal.';
}

In Example 3-14, 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 is true. These logical operators are used in Example 3-15.

Example 3-15. Logical operators
if (($age >= 13) && ($age < 65)) {
   print "You are too old for a kid's discount and too young for the senior's discount.";
}

if (($meal == 'breakfast') || ($dessert == 'souffle')) {
   print "Time to eat some eggs.";
}

The first test expression in Example 3-15 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 either of its subexpressions are 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 with parentheses each subexpression inside a larger test expression.

    Previous Section  < Day Day Up >  Next Section