# Logic in PHP: Building Complicated Decisions

The comparison and logical operators in PHP help you put together more compli­cated 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 opera­tor are shown in Example 3-6.

Example 3-6. The equal 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 equal operator is !=. It returns true if the two values that you test with it are not equal. See Example 3-7.

Example 3-7. The not-equal 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 (or equal to)

if (\$age > 17) {

}

if (\$age >= 65) {

print “You are old enough for a discount.”;

}

if (\$celsius_temp <= I ) {

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 “Numbers” on page 29, 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.

Example 3-9. Comparing floating-point numbers

if(abs(\$price_1 – \$price_2) < 0.0000 ) {

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 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.

Example 3-10. Comparing strings

if (\$word < ‘baa’) {

}

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 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.

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 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 regu­lar 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), so the greater-than comparison returns false. In the second test, each string consists entirely of numerals, so the strings are compared as num­bers. The number 54,321 is larger than the number 5,678, so the greater-than com­parison 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.

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 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 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() com­putes 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.

Example 3-13. Comparing data types with the spaceship operator

// \$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) {

print ‘The string “6 pack” is greater than the string “55 card stud”.’;

} elseif (\$x < 0) {

print ‘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) {

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.’;

}

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.

Example 3-14. 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 com­bination of it with the negation operator is false. If the value is false, then the com­bination of it with the negation operator is true. Example 3-15 shows the negation operator at work with a call to strcasecmp().

Example 3-15. The negation operator

if (! strcasecmp(\$first_name,\$last_name)) {

print ‘\$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() state­ment. 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.

Example 3-16. 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-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.

Source: Sklar David (2020), Learning PHP: A Gentle Introduction to the Web’s Most Popular Language, O’Reilly Media; 1st edition.