Saturday, December 8, 2007

Operators and Functions

Operators and Functions

We've seen several places in PHP code where values are required: most commonly, we have been telling the echo command to print out a value. We've also used values in a few other places: on the right hand side of an assignment operation, as arguments to functions, and even inside curly brackets in a complex variable reference.

There are several ways of providing a value to PHP in any of these locations. Those things which PHP is able to interpret as values for use in these situations are called expressions, and we've met three types of expression already: literals, variables, and constants.

An expression is anything that can be treated as having a value. Literals have their literal value, variables refer to a stored value, and constants do the same. However, these aren't the only types of expression in PHP. PHP supports two expression types which are evaluated to determine the value they will take on: operations and function calls.

We've seen function calls used in this way:

    echo(gettype("Hello"));

The function call (gettype("Hello")) is evaluated to provide the piece of data ("string") which is passed to the echo command. It is an expression – it has a value. This function call can, as we've said, be used in any of the places where a variable or literal could be used. The following are therefore all valid:

    $a = gettype("Hello");
${gettype("Hello")} = "World";
echo(gettype(gettype("Hello")));

The first stores the string "string" in $a, the second stores the string "World" in the variable $string, and the third prints the result of calling gettype() on the value gettype() returns.

An operation is an expression containing an operator. In the following:

    echo(2 + 2);

2 + 2 is an operation, and it has the value 4. Operators are like shorthand functions. If there was a function that provided the functionality, you could get exactly the same effect as the above by writing:

    echo(add(2, 2));

The addition operator (+) is a binary operator: it operates on two values. Other binary operators include the greater-than operator (>), the string concatenation operator (.), and the assignment operator (=).

There are also unary operators, which operate on a single value. Examples are the increment operator (++), the Boolean NOT (!), and the casting operators we met earlier, such as (int).

There is also a ternary operator, which works on three values. It should be familiar to anyone who's used a C-like language. Since there's only one, it's often referred to simply as "the ternary operator". It's the conditional operator and is used to choose between two values, depending upon the value of a third. The expression:

    $a ? $b : $c

evaluates to the value in $b if $a evaluates to true, and to the value in $c if it evaluates to false:

    echo("INDEPENDENCEDAY is " . (defined("INDEPENDENCEDAY") ? "defined" :
"not defined"));

Here the string that is printed depends on the return value of defined().

Some operators expect their operands to be of a certain type. In these circumstances, PHP will perform the type-conversion necessary to allow the operation to be performed. We saw this above with the addition operator, which expects two numerical arguments, and which forced the conversion of a string to a number before performing the addition. Other operators expect strings, or booleans, and perform similar conversions.

We'll now take a look at some of the basic operations and functions PHP provides that can be performed on values of various types.

General Operations

The most important operators are the assignment, equality, and inequality operators. They can operate on values of any type, and are used everywhere.

The assignment operator, as we've seen, is the equals sign, =. The left hand argument must be an assignable entity – generally a variable reference. The right hand argument can be any expression. The result of performing the operation is that the variable on the left is assigned the value of the expression on the right. It's important to remember, however, that the assignment operation is itself an expression: it has a value. The value it takes on is the value of the right hand expression. This means you can do the following:


echo($a = "Hello");
$a = $b = $c = "Hello";

The first prints out the value "Hello", whilst also assigning it to $a. The second assigns the value "Hello" to $c, then assigns the same value to $b, and then assigns the same value to $a.

The equality operator is a double equals, ==. It takes any two expressions as arguments, and evaluates to Boolean true if the values are equal, and Boolean false otherwise. The inequality operator, !=, returns the opposite value:

    $a = 2;
echo($a == 2);

One word of warning when working with floating-point values in PHP: the double-precision floating-point arithmetic PHP uses is not always as precise as we would like. Take a look at the following PHP code:

       $a = 1.1;
$b = 0.4;
$c = $a - $b;
echo(($c == 0.7) ? "true" : "false");
?>

This puts the floating-point values 1.1 and 0.4 into two variables, and then performs a subtraction. 1.1 minus 0.4 should be 0.7. We test to see if this is the case using the ternary operator: the first argument is an equality operation which will return true if the two values are equal, and false otherwise. The ternary operator will, then return either "true" or "false" as a string accordingly.

What should happen is that the equality test will be passed, and the word "true" will be echoed out. Unfortunately, this isn't always the case. The precision of floating-point numbers is platform-dependent, but on a 32-bit computer running Windows, this program will print out "false". This is because the floating-point value is stored as a binary number, and is only an approximation of the decimal fractions we are trying to represent. Seven tenths doesn't translate well into halves, quarters, eighths, and sixteenths.

If you are performing critical calculations and want to be able to test fractional values for equality, you will need to use some of PHP's advanced mathematical functions. You should never test floating-point values for equality.

String Operations

PHP uses the period character (.) as a string concatenation operator. This is called the dot operator:

    $a = "Hello";
$b = "World";
$c = $a . $b;
echo($c);

There is also a shorthand operator, .=:

    $a .= $b

The above is the equivalent of:

    $a = $a . $b

Remember that if you want to include spaces or new lines between elements of a string, you'll have to do it manually. You can concatenate multiple strings together using the dot operator:

    $a = "Hello";
$b = "World";
$c = "" . $a . " " . $b . "";
echo($c);

String Functions

PHP offers a wide array of string handling functions. We'll only look at the most commonly used ones here; you can find a complete list of PHP functions in the PHP manual (http://www.php.net/docs.php). We won't cover regular expressions here, but they are by far the most powerful and flexible method of manipulating strings. These are covered in depth in Chapter 7.

substr()

    string substr(string string, int start [, int length]) 

The substr() function returns a section of the string. The first argument is the complete string, the second is the position within the string of the first character you want to be returned (counting from zero), while the third is the position of the last character of the string that you want to return. If you don't specify the third argument, then PHP will assume that you just wanted to include the rest of the string. Here are some examples of substr() in action:

    $String1 = substr("The cat sat on the mat", 4,3); // 'cat'
$String2 = substr("The frog sat on the log", 0,1); // 'T'
$String3 = substr("The aardvark sat in the dark", 17); // 'in the dark'

strpos()

    int strpos(string haystack, string needle [, int offset]) 

strpos() provides the opposite functionality to the substr() function. You supply it with a subsection of a string and it returns the first place within the string that the subsection can be found (if it can be found at all).

You supply the string you wish to search first, the string you are hoping to find as the second argument, and lastly there is an optional argument which allows you to specify a position within the string to start looking from. Some examples of strpos():


$String1 = strpos("The cat sat on the mat", "cat"); // Returns '4'
$String2 = strpos("rhubarbrhubarbrhubarb", "rhubarb", 6); // Returns '7'

htmspecialchars()

    string htmlspecialchars(string string [, int quote_style
[, string charset]])

The htmlspecialchars() function is a useful little function that searches a string for certain characters which need special representation in HTML and turns them into their HTML equivalents. This function will take the following five characters and translate them into their HTML code:

  • & becomes &

  • " becomes "

  • < becomes <

  • > becomes >

The second argument takes one of two constants as an argument: ENT_QUOTES or ENT_NOQUOTES. You use the former if you wish to translate quotes and the latter if you don't. The third argument takes a string representing the character set to be used in conversion. The default is ISO-8859-1.

An example of htmlspecialchars() in action could be as follows:

    echo(htmlspecialchars("

The cat sat on the mat

",
ent_quotes));

This outputs:

    <P class='class1'>The cat sat on the mat</P>

which a web browser will use to reproduce the original characters. Useful if you want to output HTML source-code for display in a web browser.

trim()

The trim() function is straightforward: it takes one argument, a string, and removes any preceding or trailing space characters:

    $String1 = trim("   a lot of white space     "); // 'a lot of white space'

Note that you can't use trim() like this to simply trim the contents of a variable:

    $a = "  a lot of white space     ";
trim($a);

Instead, to achieve the desired effect, you should use:

    $a = trim($a);

chr() and ord()

The chr() function takes the ASCII code of a character as an argument, and returns the actual character. The ord() function does the opposite:

    echo(chr(64));   // displays '@'
echo(ord('@')); // displays '64'

strlen()

The strlen() function takes one argument, a string, and returns the length of the string in characters, as an integer. For example:

    $String1 = strlen("one"); // '3'
$String2 = strlen("the cat sat on the mat"); // '22'

printf() and sprintf()

    int printf(string format [, mixed args...])
string sprintf(string format [, mixed args...])

The printf() and sprintf() functions are two related functions that provide rather more complex functionality than the other string handling functions we have considered. They both look after the process of formatting numbers and including them in a string, and provide functionality such as returning a date in the format mm/dd/yyyy or a currency value to 2 decimal places. The sprintf() function performs the requested formatting and returns a string, while the printf() function performs the same task, but echoes the result directly to the output destination – be that the browser or console.

Conversion Specifiers

The format argument of printf()/sprintf() is a string, containing certain special characters which will be used to format the data provided in the arguments list. These special characters are called conversion specifications. Normal characters, which will appear in the formatted string unchanged, are called directives. You need to provide one argument in the list for each conversion specification which appears in the format string.

If the format contains two conversion specifications, then you should provide two arguments, and they will be formatted according to the specification and inserted into the string. They'll be placed in the location where the conversion specification appears.

A conversion specification is a percent character (%), followed by up to five specifiers, in the following order:

  • Padding Specifier
    This is used to specify a character which can be used to pad the string out to a particular size. If omitted, a space is assumed. This only has any effect if a minimum width specifier is added.

  • Alignment Specifier
    Normally, padding is added to the left of a string to extend it to the minimum width, leading to the string being right-justified, but if you add the hyphen character () then the string is left-justified.

  • Minimum Width Specifier
    This is an integer value which specifies the minimum size of the formatted string. If the string supplied is smaller than that, then the string is padded out using either a space, or the character indicated in the padding specifier, if supplied.

  • Precision Specifier
    When using fractional/floating-point numbers, you can specify how many decimal places the number should be displayed with. The specifier is written as a decimal point, followed by an integer specifying the number of decimal places which will be displayed. This specifier can also be used to format strings, and it specifies the maximum number of characters from a supplied string which will be included.

  • Type Specifier
    The type specifier is used to indicate the type of data which will be supplied in the argument, and, in the case of an integer, which mode it should be displayed in. It can be one of the following characters:

    • b – an integer presented as a binary number

    • c – an integer presented as the character with that ASCII value

    • d – an integer presented as a decimal number

    • f – a floating-point value presented as a decimal fraction (with a decimal point)

    • o – an integer presented as an octal number

    • s – a string

    • x – an integer presented as a hexadecimal number (with lowercase letters)

    • X – an integer presented as a hexadecimal number (with uppercase letters)

In addition, to include a literal percentage character in a formatted string, you must write a double percent (%%).

Let's have a look at some examples of the sprintf()/printf() functions now. We mentioned that they could be used to format dates or currencies, so let's look at some examples of this now, starting with a date:

    $day = 1;
$month = 2;
$year = 2001;
printf("%02d/%02d/%04d", $month, $day, $year);

This produces the following output:

    01/02/2001

The format includes three conversion specifications, one for the month, one for the day, and one for the year. We are formatting the month and day as two-digit integers, and the year as a four-digit integer. In order to do this, we need to specify that the integers should be padded out to a minimum length, with zeroes on the left. So, the conversion specification for the month, for example, looks like this:

    %02d

The first character is a zero, and is the padding specifier. There is no alignment specifier, because we want the padding to be added to the beginning of the number. We'll add a minimum width specifier, which is 2. We're formatting an integer, so we don't need a precision specifier. Then the last character is the type specifier, d, which tells the printf() function to format the number as a decimal integer.

The second example formats for English currency:

    $Value2 = 23;
$Value2 = sprintf("£%.2f", $Value2);

echo($Value2);

and would produce the following:

    £23.00

This floating-point conversion specifier, %.2f, simply tells the formatter to omit all but the first two digits after the decimal point. No padding or minimum length is specified, so the number to the left of the decimal point can be any length.

Numerical Operations

The basic numerical operators that you can use in PHP to perform mathematical operations should be familiar to anybody who has done math at school. They are as follows:

Operator

Operation

+

The addition operator

*

The multiplication operator

The subtraction operator

/

The division operator

%

The modulus operator (works out the remainder left by division) e.g. 8 % 5 is 3

In most cases, if the arguments are both integers, they will return an integer, but if you include a floating-point value, they will return a floating-point value – even if the result has no fractional component. 1.5 plus 1.5 is 3.0, not 3.

There are assignment variants of all of these operators. To save you from having to write $a = $a + $b, you can use the shorthand $a += $b. Similar versions exist for all of the above operators.

For addition and subtraction, there are two other shorthand operators: the increment (++) and decrement (−− ) operators. There is a slight subtlety in the use of these unary operators, depending on whether you see them before or after the operand. This doesn't matter much when you use them as below, simply to increase the value of a variable. These two code snippets are identical:

    $a = 1;
$a++;


$a = 1;
++$a;

The difference happens when you look at the value returned by the increment operation in each case. Remember we said all operations are actually expressions – they return a value. The result of the following will be that the number 1 gets sent as output:


$a = 1;
echo($a++);

This is because a postpended increment operator returns the value of its operand, and then increases it by one. On the other hand, this code:

    $a = 1;
echo(++$a);

will print out 2. The prepended increment operator performs the increment first, and then returns the resulting value. The decrement operator acts in the same way.

Bitwise Operators

Another set of operators also work with numerical values – bitwise operators. These operate on the binary data underlying integer values as a string of bits. There are bitwise AND (&), OR (|), XOR (^), NOT (~), shift left (<<), and shift right (>>) operators. You can use these to create sets of Boolean flags. Here is an example of a set of flags, which signify user permissions:

       define(CREATE_RECORDS, 1);
define(DELETE_RECORDS, 2);
define(ALTER_RECORDS, 4);
define(ADMINISTRATOR, 8);

$user_permissions = CREATE_RECORDS | ALTER_RECORDS;

echo(($user_permissions & CREATE_RECORDS) ? "user can create records
" : "");
echo(($user_permissions & DELETE_RECORDS) ? "user can delete records
" : "");
echo(($user_permissions & ALTER_RECORDS) ? "user can alter records
" : "");
echo(($user_permissions & ADMINISTRATOR) ? "user is an administrator
": "");
?>

We create a set of constants whose values are all powers of two – the integers 1, 2, 4, and 8. In binary, these are 0001, 0010, 0100, and 1000. Then we build a set of user permissions out of these constants using the binary OR operator. The value of the $user_permissions variable is actually set to 1 OR 4, which is in fact 5: 0101. The flags for "create records" and "alter records'"have been set.

Then we test the user's permissions against each of the constants using the binary AND operator. If the user permission flag for one of the values is set, then ANDing the values together will create a non-zero value. If the flag isn't set, the result of the AND operation will be zero. If the result is zero, nothing is printed – if it's non-zero, the relevant string is output.

Like the arithmetic operators, there is an assignment version of the AND, OR, and XOR operators. For an example, add the following line to the program:

       define(CREATE_RECORDS, 1);
define(DELETE_RECORDS, 2);
define(ALTER_RECORDS, 4);
define(ADMINISTRATOR, 8);
$user_permissions = CREATE_RECORDS | ALTER_RECORDS;
$user_permissions |= DELETE_RECORDS;

echo(($user_permissions & CREATE_RECORDS) ? "user can create records
" : "");
echo(($user_permissions & DELETE_RECORDS) ? "user can delete records
" : "");
echo(($user_permissions & ALTER_RECORDS) ? "user can alter records
" : "");
echo(($user_permissions & ADMINISTRATOR) ? "user is an administrator
": "");
?>

The shift left and shift right operators shift the bits of the specified integer left or right by the amount specified. Each step is equivalent to multiplying or dividing by two, respectively:

    define(TWO, 2);
define(FOUR, 4);

echo(TWO << FOUR); // 32
echo(FOUR >> TWO); // 1

Comparison Operators

The final set of operators used in conjunction with numbers is the comparison operators: less-than (<), less-than-or-equal (<=), greater-than (>), and greater-than-or-equal (>=). All of these compare the two values they are given and return either true or false.

Operator Precedence

These simple mathematical operations begin to become more complex when combined. The following statement is, on the face of it, quite simple, but also ambiguous:

    $sum = 5 + 3 * 6;

If you calculate it in the strict order as it appears, you'll end up with 48. However, following the mathematical order of precedence, you'll come up with the total 23. Clearly you need C-style rules to sort out operation order. PHP follows the ordering below when evaluating an expression which contains more than one operator:

Numerical Operators

++, , ~, casting operators

*, /, %

+,

<, <=, >, >=

==, !=

&

^

|

As in mathematics, PHP uses parentheses to override these rules of precedence. So, to get 48:

    $Sum = (5+3)*6;

Logical Operators

The logical operators are used to test Boolean conditions. PHP has operators for the four main Boolean conditions: AND (and or &&), OR (or or ||), NOT (!), and XOR (xor). AND and OR have two different operators because they have different precedences.

Here is an example of the logical operators in action:

    if (file_exists("travel.xml") && is_readable("travel.xml")) {
fopen("travel.xml", r);
echo("travel.xml opened");
} else {
echo("travel.xml not opened");
}

This code snippet checks to see that travel.xml exists AND that travel.xml is readable before it is opened for reading.

Operator Precedence

The logical operators also have a precedence associated with them:

Logical Operators

or

xor

and

||

&&

!

No comments: