Web Database Applications with PHP \& MySQLWeb Database Applications with PHP \& MySQLSearch this book

2.5. Arrays

Arrays in PHP are sophisticated and more flexible than in many other high-level languages. An array is an ordered set of variables, in which each variable is called an element. Technically, arrays can be either numbered or associative, which means that the elements of an array can be accessed by a numeric index or by a textual string, respectively.

In PHP, an array can hold scalar values—integers, Booleans, strings, or floats—or compound values—objects and even other arrays, and can hold values of different types. In this section, we show how arrays are constructed and introduce several useful array functions from the PHP library.

2.5.1. Creating Arrays

PHP provides the array( ) language construct that creates arrays. The following examples show how arrays of integers and strings can be constructed and assigned to variables for later use:

$numbers = array(5, 4, 3, 2, 1);
$words = array("Web", "Database", "Applications");

// Print the third element from the array 
// of integers: 3
echo $numbers[2];

// Print the first element from the array 
// of strings: "Web"
echo $words[0];   

By default, the index for the first element in an array is 0. The values contained in an array can be retrieved and modified using the bracket [ ] syntax. The following code fragment illustrates the bracket syntax with an array of strings:

$newArray[0] = "Potatoes";
$newArray[1] = "Carrots";
$newArray[2] = "Spinach";

// Oops, replace the third element
$newArray[2] = "Tomatoes";

Numerically indexed arrays can be created to start at any index value. Often it's convenient to start an array at index 1, as shown in the following example:

$numbers = array(1=>"one", "two", "three", "four");

Arrays can also be sparsely populated, such as:

$oddNumbers = array(1=>"one", 3=>"three", 5=>"five");

An empty array can be created by assigning a variable with no parameters with array( ). Values can then be added using the bracket syntax. PHP automatically assigns the next numeric index—the largest current index plus one—when an index isn't supplied. Consider the following example, which creates an empty array $errors and tests whether that array is empty at the end of the script. The first error added with $errors[] is element 0, the second is element 1, and so on:

$errors = array( );

// later in the code ..
$errors[] = "Found an error";

// ... and later still
$errors[] = "Something went horribly wrong";

// Now test for errors
if (empty($errors))
  // Phew. We can continue
  echo "Phew. We can continue";
else
  echo "There were errors";

2.5.1.1. Associative arrays

An associative array uses string indexes—or keys—to access values stored in the array. An associative array can be constructed using array( ), as shown in the following example, which constructs an array of integers:

$array = array("first"=>1, "second"=>2, "third"=>3);

// Echo out the second element: prints "2"
echo $array["second"];

The same array of integers can also be created with the bracket syntax:

$array["first"] = 1;
$array["second"] = 2;
$array["third"] = 3;

There is little difference between using numerical or string indexes to access values. Both can reference elements of an associative array, but this is confusing and should be avoided in practice.

Associatively indexed arrays are particularly useful for interacting with the database tier. Arrays are used extensively in Chapter 4, Chapter 5, and Chapter 6, and more examples and array-specific functions are presented there.

2.5.1.2. Heterogeneous arrays

The values that can be stored in a single PHP array don't have to be of the same type; PHP arrays can contain heterogeneous values. The following example shows the heterogeneous array $mixedBag:

$mixedBag = array("cat", 42, 8.5, false);

var_dump($mixedBag);

The function var_dump( ) displays the contents (with a little whitespace added for clarity):

array(4) { [0]=> string(3) "cat" 
           [1]=> int(42) 
           [2]=> float(8.5) 
           [3]=> bool(false) }

2.5.1.3. Multidimensional arrays

PHP arrays can also hold other arrays creating multidimensional arrays. Example 2-4 shows how multidimensional arrays can be constructed.

Example 2-4. Examples of multidimensional arrays in PHP

<!DOCTYPE HTML PUBLIC
   "-//W3C//DTD HTML 4.0 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd" >
<html>
<head>
  <title>Multi-dimensional arrays</title>
</head>
<body bgcolor="#ffffff">
<h2>A two dimensional array</h2>
<?php

  // A two dimensional array using integer indexes
  $planets = array(array("Mercury", 0.39, 0.38),
                   array("Venus", 0.72, 0.95),
                   array("Earth", 1.0, 1.0),
                   array("Mars", 1.52, 0.53) );

  // prints "Earth"
  print $planets[2][0]
?>

<h2>More sophisticated multi-dimensional array</h2>
<?php

  // More sophisticated multi-dimensional array
  $planets2 = array(
    "Mercury"=> array("dist"=>0.39, "dia"=>0.38),
    "Venus"  => array("dist"=>0.39, "dia"=>0.95),
    "Earth"  => array("dist"=>1.0,  "dia"=>1.0,
                  "moons"=>array("Moon")),
    "Mars"   => array("dist"=>0.39, "dia"=>0.53,
                  "moons"=>array("Phobos", "Deimos")),
  );

  // prints "Moon"
  print $planets2["Earth"]["moons"][0];
?>
</body>
</html>

The first array constructed in Example 2-4 is two-dimensional and is accessed using integer indexes. The array $planets contains four elements, each of which is an array that contains three values: the planet name, the distance from the Sun, and the planet diameter relative to the Earth.

The second array in Example 2-4 is a little more sophisticated: the array $planets2 uses associative keys to identify an array that holds information about a planet. Each planet has an array of values that are associatively indexed by the name of the property that is stored; the array is effectively acting like a property list. For those planets that have moons, an extra property is added that holds an array of the moon names.

As stated in the introduction to this section, PHP arrays are very flexible. Many data structures—such as property lists, stacks, queues, and trees—can be created using arrays. We limit our usage of arrays to simple structures; the examination of more complex data structures is outside the scope of this book.

2.5.2. Using foreach Loops with Arrays

As we discussed earlier, the easiest way to iterate through—or traverse—an array is using the foreach statement.The foreach statement was specifically introduced in PHP4 to make working with arrays easier.

The foreach statement has two forms:

foreach(array_expression as $value) statement
foreach(array_expression as $key => $value) statement

Both iterate through an array expression, executing the body of the loop for each element in the array. The first form assigns the value from the element to a variable identified with the as keyword; the second form assigns both the key and the value to a pair of variables.

The following example shows the first form in which the array expression is the variable $lengths, and each value is assigned to the variable $cm:

// Construct an array of integers
$lengths = array(0, 107, 202, 400, 475);

// Convert an array of centimeter lengths to inches
foreach($lengths as $cm)
{
  $inch = $cm / 2.54;
  echo "$cm centimeters = $inch inches\n";
}

The example iterates through the array in the same order it was created:

0 centimeters = 0 inches 
107 centimeters = 42.125984251969 inches
202 centimeters = 79.527559055118 inches
400 centimeters = 157.48031496063 inches
475 centimeters = 193.87755102041 inches

The first form of the foreach statement can also iterate through the values of an associative array, however the second form assigns both the key and the value to variables identified as $key => $value. The next example shows how the key is assigned to $animal, and the value is assigned to $sound to generate verses of "Old MacDonald":

// Old MacDonald
$sounds = array("cow"=>"moo", "dog"=>"woof",
                "pig"=>"oink", "duck"=>"quack");

foreach ($sounds as $animal => $sound)
{
  echo "<p>Old MacDonald had a farm EIEIO";
  echo "<br>And on that farm he had a $animal EIEIO";
  echo "<br>With a $sound-$sound here"; 
  echo "<br>And a $sound-$sound there"; 
  echo "<br>Here a $sound, there a $sound"; 
  echo "<br>Everywhere a $sound-$sound"; 
}

This prints a verse for each $animal/$sound pair in the $sounds array:

Old MacDonald had a farm EIEIO
And on that farm he had a cow EIEIO
With a moo-moo here
And a moo-moo there
Here a moo, there a moo
Everywhere a moo-moo

Old MacDonald had a farm EIEIO
And on that farm he had a dog EIEIO
With a woof-woof here
And a woof-woof there
Here a woof, there a woof
Everywhere a woof-woof

When the second form of the foreach statement is used with a nonassociative array, the index is assigned to the key variable and the value to the value variable. The following example uses the index to number each line of output:

// Construct an array of integers
$lengths = array(0, 107, 202, 400, 475);

// Convert an array of centimeter lengths to inches
foreach($lengths as $index => $cm)
{
  $inch = $cm / 2.54;
  $item = $index + 1;
  echo $index + 1 . ". $cm centimeters = $inch inches\n";
}

The foreach statement is used throughout Chapter 4 to Chapter 13.

2.5.3. Using Array Pointers

Along with the keys and the associated values stored in an array, PHP maintains an internal index that points to the current element in the array. Several functions use and update this array index to provide access to elements in the array. To illustrate how this internal index can be used, consider the following example:

$a = array("a", "b", "c", "d", "e", "f");
echo current($a  );     // prints "a"

// Array ( [1]=> a [value]=> a [0]=> 0 [key]=> 0 )
print_r each($a);

// Array ( [1]=> b [value]=> b [0]=> 1 [key]=> 1 )
print_r each($a);

// Array ( [1]=> c [value]=> c [0]=> 2 [key]=> 2 )
print_r each($a);

echo current($a  );     // prints "d"

The internal index is set to point at the first element when a new array is created, and the function current( ) returns the value pointed to by the array's internal index. The function each( ) returns an array that holds the index key and the value of the current element, and then increments the internal index of the array to point at the next element. The array each( ) returns has four elements: two that hold the key, accessed by the numeric index 0 and the associative key key; and two that hold the value, accessed by the numeric index 1 and the associative key value.

Other functions that use the array's internal pointer are end( ), next( ), prev( ), reset( ), and key( ).

Before the foreach statement was introduced to the PHP language, a common way to iterate through an associative array was to use a while loop with the each( ) function to get the key/value pairs for each element and the list( ) function to assign these values to variables. The following example shows how such an iteration is performed through the $sounds array to generate verses of "Old MacDonald":

$sounds = array ("pig"=>"oink", "cow"=>"moo", 
                 "duck"=>"quack", "dog"=>"woof");

while (list($animal, $sound) = each($sounds))
{
  echo "<p>Old MacDonald had a farm EIEIO";
  echo "<br>And on that farm he had a $animal EIEIO";
  echo "<br>With a $sound-$sound here"; 
  echo "<br>And a $sound-$sound there";  
  echo "<br>Here a $sound, there a $sound"; 
  echo "<br>Everywhere a $sound-$sound"; 
}

The foreach statement is clearer and should be used in most cases. However we include the while loop example here because many existing scripts use this structure to iterate through an associative array.

The list( ) function isn't really a function, but a language construct that assigns multiple variables from an array expression:

list($var1, $var2, ...) = array_expression

list( ) appears on the left side of an assignment and an array expression appears on the right. The arguments to list( ) must be variables. The first variable is assigned the value of the first element in the array, the second variable the value from the second element, and so on. We avoid using the list( ) construct, because its use leads to assumptions about the number of elements in an array. The need to use list( ) to access the key/value pairs returned from each( ) is avoided with the foreach statement.

2.5.4. Basic Array Functions

In this section, we introduce selected basic PHP array library functions.

2.5.4.1. Counting elements in arrays

The count( ) function returns the number of elements in the array var:

integer count(mixed var)

The following example prints 7 as expected:

$days = array("Mon", "Tue", "Wed", "Thu", 
              "Fri", "Sat", "Sun");

echo count($days);  // 7

The count( ) function works on any variable type and returns 0 when either an empty array or a variable that isn't set is examined. If there is any doubt, isset( ) and is_array( ) should be used to check the variable being considered.

2.5.4.2. Finding the maximum and minimum values in an array

The maximum and minimum values can be found from an array numbers with max( ) and min( ), respectively:

number max(array numbers)
number min(array numbers)

If an array of integers is examined, the returned result is an integer, if an array of floats is examined, min( ) and max( ) return a float:

$var = array(10, 5, 37, 42, 1, -56);
echo max($var);  // prints 42
echo min($var);  // prints -56

Both min( ) and max( ) can also be called with a list of integer or float arguments:

number max(number arg1, number arg2, number arg3, ...)
number min(number arg1, number arg2, number arg3, ...)

Both max( ) and min( ) work with strings or arrays of strings, but the results may not always be as expected.

2.5.4.3. Finding values in arrays with in_array( ) and array_search( )

The in_array( ) function returns true if an array haystack contains a specific value needle:

boolean in_array(mixed needle, array haystack [, boolean strict])

The following example searches the array of integers $smallPrimes for the integer 19:

$smallPrimes = array(3, 5, 7, 11, 13, 17, 19, 23, 29);

if (in_array(19, $smallPrimes)) 
  echo "19 is a small prime number"; // Always printed

A third, optional argument can be passed that enforces a strict type check when comparing each element with the needle. In the following example in_array( ) by default returns true; however, with strict type checking, the string "19" doesn't match the integer 19 held in the array and returns false:

$smallPrimes = array(3, 5, 7, 11, 13, 17, 19, 23, 29);

if (in_array("19", $smallPrimes, true))
  echo "19 is a small prime number"; // NOT printed

The array_search( ) function—introduced with PHP 4.0.5—works the same way as the in_array( ) function, except the key of the matching value needle is returned rather than the Boolean value true:

mixed array_search(mixed needle, array haystack [, boolean strict])

However, if the value isn't found, array_search( ) returns false. The following fragment shows how array_search( ) works with both associative and indexed arrays:

$measure = array("inch"=>1, "foot"=>12, "yard"=>36);

// prints "foot"
echo array_search(12, $measure);

$units = array("inch", "centimeter", "chain", "furlong");

// prints 2
echo array_search("chain", $units);

Because array_search( ) returns a mixed result—the Boolean value false if the value isn't found or the key of the matching element—a problem is encountered when the first element is found. PHP's automatic type conversion treats the value 0—the index of the first element—as false in a Boolean expression.

WARNING: Care must be taken with functions, such as array_search( ), that return a result or the Boolean value false to indicate when a result can't be determined. If the return value is used as a Boolean—in an expression or as a Boolean parameter to a function—a valid result may be automatically converted to false. If such a function returns 0, 0.0, "c", an empty string, or an empty array, PHP's automatic type conversion converts the result to false when a Boolean value is required.

The correct way to test the result is to use the is-identical operator ===, as shown in the following example:

$index = array_search("inch", $units);

if ($index === false)
  echo "Unknown unit: inch";
else
  // OK to use $index
  echo "Index = $index";

2.5.4.4. Reordering elements in arrays with array_reverse( )

Often it's useful to consider an array in reverse order. The array_reverse( ) function creates a new array by reversing the elements from a source array:

array array_reverse(array source [, bool preserve_keys])

The following example shows how to reverse an indexed array of strings:

$count = array("zero", "one", "two", "three");

$countdown = array_reverse($count);

Setting the optional preserve_keys argument to true reverses the order but preserves the association between the index and the elements. For a numerically indexed array, this means that the order of the elements is reversed, but the indexes that access the elements don't change. This might seem a bit weird, but the following example shows what is happening:

$count = array("zero", "one", "two", "three");
$countdown = array_reverse($count, true);
print_r($countdown);

This prints:

Array ([3] => three [2] => two [1] => one [0] => zero)

2.5.5. Sorting Arrays

In the previous section we showed how to reverse the elements of an array. In this section we show how to sort arrays. Unlike the array_reverse( ) function that returns a copy of the source array in the new order, the sorting functions rearrange the elements in the source array itself. Because of this behavior, the sort functions must be passed a variable, not an expression.

2.5.5.1. Sorting with sort( ) and rsort( )

The simplest array-sorting functions are sort( ) and rsort( ), which rearrange the elements of the subject array in ascending and descending order, respectively:

sort(array subject [, integer sort_flag])
rsort(array subject [, integer sort_flag])

Both functions sort the subject array based on the values of each element. The following example shows the sort( ) function on an array of integers:

$numbers = array(24, 19, 3, 16, 56, 8, 171);
sort($numbers);

foreach($numbers as $n)
  echo $n . " ";

The output of the example prints the elements sorted by value:

3 8 16 19 24 56 171

Another way to examine the contents of the sorted array is to use the print_r( ) function described in Section 2.1.7. The output of the statement print_r($numbers) shows the sorted values with the associated index:

Array ( [0] => 3 
        [1] => 8 
        [2] => 16 
        [3] => 19 
        [4] => 24 
        [5] => 56 
        [6] => 171 ) 

The following example shows the rsort( ) function on the same array:

$numbers = array(24, 19, 3, 16, 56, 8, 171);
rsort($numbers);
print_r($numbers);

The output of the example shows the elements sorted in reverse order by value:

Array ( [0] => 171 
        [1] => 56 
        [2] => 24 
        [3] => 19 
        [4] => 16 
        [5] => 8 
        [6] => 3 ) 

By default, PHP sorts strings in alphabetical order and numeric values in numeric order. An optional parameter, sort_flag, can be passed to force the string or numeric sorting behavior. In the following example, the PHP constant SORT_STRING sorts the numbers as if they were strings:

$numbers = array(24, 19, 3, 16, 56, 8, 171);
sort($numbers, SORT_STRING);
print_r($numbers);

The output of the example shows the result:

Array ( [0] => 16 
        [1] => 171 
        [2] => 19 
        [3] => 24 
        [4] => 3 
        [5] => 56 
        [6] => 8 ) 

Many of the array sorting functions accept a sort_flag parameter. Other sort flags are SORT_REGULAR to compare items in the array normally and SORT_NUMERIC that forces items to be compared numerically.

sort( ) and rsort( ) can be used on associative arrays, but the keys are lost. The resulting array contains only the values in the sorted order. Consider the following example:

$map = 
  array("o"=>"kk", "e"=>"zz", "z"=>"hh", "a"=>"rr");

sort($map);
print_r($map);

The print_r( ) output shows the modified array without the key values:

Array ( [0] => hh [1] => kk [2] => rr [3] => zz ) 

2.5.5.2. Sorting associative arrays

It's often desirable to keep the key/value associations when sorting associative arrays. To maintain the key/value association the asort( ) and arsort( ) functions are used:

asort(array subject [, integer sort_flag])
arsort(array subject [, integer sort_flag])

Like sort( ) and rsort( ), these functions rearrange the elements in the subject array from lowest to highest and highest to lowest, respectively. The following example shows a simple array sorted by asort( ):

$map =
  array("o"=>"kk", "e"=>"zz", "z"=>"hh", "a"=>"rr");

asort($map);
print_r($map);

The print_r( ) function outputs the structure of the sorted array:

Array ( [z] => hh 
        [o] => kk 
        [a] => rr 
        [e] => zz ) 

When assort( ) and arsort( ) are used on nonassociative arrays, the order of the elements is arranged in sorted order, but the indexes that access the elements don't change. This might seem a bit weird; effectively the indexes are treated as association keys in the resulting array. The following example shows what is happening:

$numbers = array(24, 19, 3, 16, 56, 8, 171);
asort($numbers);
print_r($numbers);

This outputs:

Array ( [2] => 3 
        [5] => 8 
        [3] => 16 
        [1] => 19 
        [0] => 24 
        [4] => 56 
        [6] => 171 ) 

2.5.5.3. Sorting on keys

Rather than sort on element values, the ksort( ) and krsort( ) functions rearrange elements in an array by sorting on the keys or the indexes:

integer ksort(array subject [, integer sort_flag])
integer krsort(array subject [, integer sort_flag])

ksort( ) sorts the elements in the subject array from lowest key to highest key, and krsort( ) sorts in the reverse order. The following example demonstrates the ksort( ) function:

$map =
  array("o"=>"kk", "e"=>"zz", "z"=>"hh", "a"=>"rr");

ksort($map);
print_r($map);

The sorted array $map is now:

Array ( [a] => rr 
        [e] => zz 
        [o] => kk 
        [z] => hh ) 

There is little point in using ksort( ) on an integer-indexed array because the keys are already in order. When krsort( ) is used on an indexed array, it reverses the order of the elements.

2.5.5.4. Sorting with user-defined element comparison

The sorting functions described so far in this section sort elements in alphabetic, numeric, or alphanumeric order. To sort elements based on user-defined criteria, PHP provides three functions:

usort(array subject, string compare_function)
uasort(array subject, string compare_function)
uksort(array subject, string compare_function)

usort( ) sorts the subject array based on the value of each element, uasort( ) preserves the key/value associations as described earlier for the asort( ) function, and uksort( ) rearranges the elements based on the key of each element. When these functions sort the subject array, the user-defined compare function is called to determine if one element is greater than, lesser than, or equal to another. The compare function can be written to implement any sort order, but the function must conform to the prototype:

integer my_compare_function(mixed a, mixed b)

We discuss how to write functions in more detail in Section 2.10. The compare function takes two arguments, a and b, and returns -1 if a is less than b, 1 if a is greater than b, and 0 if a and b are equal. How the function determines that one value is less than, greater than, or equal to another depends on the requirements of sorting. The following example shows how usort( ) sorts an array of strings based on the length of each string:

// Compare two string values based on the length
function cmp_length($a, $b) 
{   
  if (strlen($a) < strlen($b)) return -1;
  if (strlen($a) > strlen($b)) return 1;
     
  // String lengths must be equal
  return 0;
}

$animals = 
  array("cow", "ox", " hippopotamus", "platypus");

usort($animals, "cmp_length");

print_r($animals);

The array $animals is printed:

Array ([0]=>ox [1]=>cow [2]=>platypus [3]=>hippopotamus)

In this example, cmp_length( ) is defined as the compare function, but it isn't called directly by the script. The name of the function, "cmp_length", is passed as an argument to usort( ), and usort( ) uses cmp_length( ) as part of the sorting algorithm. User-defined functions used in this way are often referred to as callback functions.

PHP has several library functions that allow user-defined behavior through user-defined callback functions. The array_map( ) and array_walk( ) functions allow user-defined functions to be applied to the elements of an array. We provide another example in Appendix D where we implement user-defined session management.



Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.