You've already encountered arrays in this book, but now it's time to explore them in depth. An array is a set of variables that all have the same name but a different index. Each member of the array is called an element. You create arrays in the same way you create variables, except that each element's name must be followed by its index in square brackets:
$states_of_the_USA[1] = "Washington";
$states_of_the_USA[2] = "California";
Because the index numbers are numeric values, no quotes are required to specify them in the array name.
You don't have to assign values to the elements in order numerically; you can enter values in any order, and with or without any particular index number associated with them:
$ states_of_the_USA[49]="Alaska";
$ states_of_the_USA[13]="Alabama";
In fact, you don't have to use numeric indexing at all—you can use characters instead. The characters are inside quotes inside the brackets. Arrays having names for elements rather than index numbers are often known as associative arrays:
If you want to access the contents of an associative array, using quotation marks around the element name is optional. For example, to echo out Sacramento, you can type either:
echo $state_capital["CA"];
or
echo $state_capital[CA];
Both get it displayed on the Web page. The online documentation says that eventually the ability to access array elements by name without using quotes may change, but for now it works fine.
One last feature of arrays in PHP is that you can actually assign different data types and variables to the values within the array. Here are some examples:
$number[1]=24;
$number[2]="twenty three";
$number[2]=$variable;
$number["CA"]=$variable;
However, this poses a couple of questions. How does PHP know how big an array should be? And how much memory should it assign to an array? The answers to these questions are in the following sections.
Initialization of Arrays
Setting the initial values of array variables is, not surprisingly, a process known as initialization. You've seen the two ways to initialize arrays (create an array variable by naming it and setting its value) in this book already: you don't worry about the indexing and let PHP do it for you automatically. You create one item in the array, and then you create another with the same name:
$author[]="William Shakespeare";
$author[]="Franz Kafka";
Without the square brackets, PHP wouldn't know that you're dealing with array variables, and would replace the first value with the second one. The brackets indicate that you want to store the values in an array. The lack of an index value lets PHP decide where to put them. You'll find that if the $author[] array hasn't been used before, then the values in this example would be stored in $author[0] and $author[1]. PHP will carry on assigning new values to the next element in the array.
And of course the second way to initialize an array is to use explicit index values:
$author[0]="William Shakespeare";
$author[1]="Franz Kafka";
Here you don't have to abide by the constraints of auto-numbering that PHP otherwise imposes on you; and you can assign index values out of sequence, as described earlier. Where arrays are concerned, PHP is different from many programming languages on two counts. First, you don't have to predefine the data type of the array, stating whether it will contain numbers or text. This is consistent with PHP's policy on variables: you don't have to choose a data type; PHP does it for you. Second, you also don't have to specify how large the array is before it is created because PHP determines how large the maximum index number in the array needs to be.
There are two more ways of populating arrays in PHP and both make use of the array() construct. The first assigns values directly, without specifying anything about the index numbers or array elements. For example, the authors code snippet can be redefined as follows:
$author = array ("William Shakespeare", "Franz Kafka");
Again, this asks PHP to automatically generate the index values.
There are no size limits on arrays like these, so you could also write the following line:
$states_of_the_USA = array ("Alabama", "Alaska", "Arizona",Arkansas",
"California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia",
"Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
"Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire",
"New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota",
"Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South
Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
"Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming");
PHP will automatically generate the index values, with the first state receiving an index value of zero, and Wyoming having the value 49.
However, this can be a little counter-intuitive; you know there are 50 states in the USA, and if you finish with 49, you get that niggling feeling that one has been left out. The second way to create an array variable using the array() function gets you around this. It makes use of the => operator to enable you to pick the index you want the array to start at:
$states_of_the_USA = array (1 => "Alabama", "Alaska", Arizona", "Arkansas",
"California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia",
"Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
"Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire",
"New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota",
"Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina",
"South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia",
"Washington", "West Virginia", "Wisconsin", "Wyoming");
In other words, you place the number you want the index to start at, followed by the => operator, and then your list of values as normal. Now if you echo the contents of $states_of_the_USA[50], it would be Wyoming. It doesn't have to be 1, it equally be 101, and then Wyoming would have the index of 150.
If you want to index a large associative array, then you have to set each value individually. Again, the code makes use of the => operator. For example, with the states, it might be as follows:
$states_of_the_USA = array ("al" => "Alabama", "ak" => "Alaska", "az" => "Arizona", "ar" => "Arkansas", "ca", => "California", "co", => "Colorado", "ct", => "Connecticut", "de", => "Delaware", "fl", => "Florida", "ga" => Georgia", "hi" => "Hawaii", "id" => "Idaho", "il" => "Illinois", "in" => "Indiana", "ia" => "Iowa", "ks" => "Kansas", "ky" => "Kentucky", "la" => "Louisiana", "me" => "Maine", "md" => "Maryland", "ma" => "Massachusetts", "mi" => "Michigan", "mn" => "Minnesota", "ms" => "Mississippi", "mo" => "Missouri", "mt" => "Montana", "ne" => "Nebraska", "nv" => "Nevada", "nh" => "New Hampshire", "nj" => "New Jersey"; "nm" => "New Mexico", "ny" => "New York", "nc" => "North Carolina", "nd" => "North Dakota", "oh" => "Ohio", "ok" => "Oklahoma", "or" => "Oregon", "pa" => "Pennsylvania", "ri" => "Rhode Island", "sc" => "South Carolina", "sd" => "South Dakota", "tn" => "Tennessee", "tx" => "Texas", "ut" => "Utah", "vt" => "Vermont", "va" => "Virginia", "wa" => "Washington", "wv" => "West Virginia", "wi" => "Wisconsin", "wy" => "Wyoming");
Slow, but it does the job.
Iterating Through an Array
If you've created an array with lots of entries, you don't want to have to go back and individually retrieve each item in the array. It makes for a lot of extra work. This is where loops work hand-in-hand with arrays. If you want to print out the name of each of the 50 states on your Web page, you can just use the for loop to do it for you. To display all 50 states in the 1 to 50 indexed $states_of_the_USA array would take a grand total of three lines, excluding the line that creates the array:
for ($counter=1; $counter<51; $counter++) {
echo"<BR>$states_of_the_USA[$counter]";
}
The line between the braces selects an element from the $states_of_the_USA array, by placing the variable $counter between the brackets to use as the index. Because $counter is a variable, the index can then be changed by changing the value of $counter. The for loop says, "Start the counter at one, and go up to the value 50, in increments of one." So the $counter variable is substituted for 1, 2, 3, and so on, for each iteration (that <br> is used to display each state on a new line):
echo"<br>$states_of_the_USA[1];
echo"<br>$ states_of_the_USA[2];
echo"<br>$ states_of_the_USA[3];
etc ...
There's nothing to preclude you from using while or do while loops, although you'd have to create a loop counter and set it yourself. The following while loop would do the same as the for loop:
$counter = 1;
while ($counter < 51) {
echo"<br> $states_of_the_USA[$counter]";
$counter = $counter + 1;
}
It just takes an extra couple of lines to do it, that's all.
Ready to try your hand at iterating through an array?
Try it Out: Iterate Through an Array
Sticking with the states, you're going to create two arrays in this example, one that holds all of the states' names, and one that holds the names of all of the states' capitals. You'll be able to select the name of a state from a drop-down list box, and the program will search through the corresponding array to find the state capital. You'll employ loops and arrays several times to ensure that you don't have to create 50 lines of HTML to display any of the answers.
-
Open your favorite Web page editor and type in the following:
<html> <head><title></title></head> <body> <?php if (isset($_POST['posted'])) { $state_capital = array (0 => "Montgomery", "Juneau", "Phoenix", "Little Rock", "Sacramento", "Denver", "Hartford", "Dover", "Tallahasse", "Atlanta", "Honolulu", "Boise", "Springfield","Indianapolis", "Des Moines", "Topeka", "Frankfort", "Baton Rouge", "Augusta", "Annapolis", "Boston", "Lansing", "Saint Paul", "Jackson", "Jefferson City", "Helena", "Lincoln", "Carson City", "Concord", "Trenton", "Santa Fe", "Albany", "Raleigh", "Bismarck", "Columbus", "Oklahoma City", "Salem", "Harrisburg", "Providence", "Columbia", "Pierre", "Nashville", "Austin", "Salt Lake City", "Montpelier", "Richmond", "Olympia", "Charleston", "Madison", "Cheyenne"); for ($counter=0; $counter<50; $counter++) { if($_POST['hiddenstate'][$counter]==$_POST('state']) { echo"The state capital of $_POST['state'] is <b>$state_capital[$counter]</b><hr>"; } } } ?> <form action="capitals.php" method="POST"> <input type="hidden" name="posted" value="true"> What state do you want to know the capital of? <select name="state"> <?php $states_of_the_USA = array (1 => "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"); for ($counter = 1; $counter < 51; $counter ++) { echo"<option>$states_of_.the_USA[$counter]</option>"; } echo "</select><br><br>" ; for ($counter = 1; $counter < 51; $counter++) { echo"<input type='hidden' name='hiddenstate[]' value='$states_of_the_USA[$counter]'>"; } ?> <input type="submit" value="Find Capital"> </form> </body> </html>
-
Save the file as capitals.php. and close it.
-
Open the file in your browser and select a state.
-
Click the Find Capital button to get an answer: Figure 4-11 shows the answer for a user who selected the state of Hawaii.
How it Works
This example demonstrates exactly how much code you can save by using loops and arrays. If only it could have saved you from typing the data in as well!
For this example, the first page was changed into a PHP one so that you could use PHP's array() function to avoid typing in 50 lines of HTML in the <select> list box. It starts by creating an HTML form:
<form action="capitals.php" method=post>
What state do you want to know the capital of?
Next you create a drop-down list box:
<select name="state">
Moving into the PHP script, the names of the states are fed into an array called $states_of_the_USA, beginning at index 1:
<?php $states_of_the_USA = array (1 => "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming");
A loop is created to iterate 50 times, placing the name of each state in the list box.
for ($counter = 1; $counter < 51; $counter ++) {
echo"<option>$ states_of_the_USA[$counter]</option>";
}
echo "</select><br><br>";
When the loop is finished, the list box is closed. You might have expected the next line to supply a Submit button and to close the form. However, a problem arises here if you think ahead to the next page: you need all of the states to be available on the next page, not just this page. Why? Well, consider how you find the state capital of a particular state. You locate the index of the state in the $states_of_the_USA array, and then look up the state capital that's present at the same index of the $state_capital array. For example, the contents of $states_of_the_USA[1] is Alabama, so the contents of $state_capital[1] is Montgomery. You can do this because you made sure that the capital at any particular index in $state_capital is the capital of the state located at the same index in $states_of_the_USA. In other words, the data in the two arrays correspond by index.
Now, if you passed only the state selected from the list box to the next script, then you wouldn't be passing along the index of this state within $states_of_the_USA. Without that information, you can't look up the corresponding index of $state_capital and find the capital of the selected state.
What can you do? Obviously, you need to pass some information about the index of the state to the next script, so you simply pass the full array of states to the next script.
Create a second loop, and use it to create an array containing 50 hidden controls, $_POST['hiddenstate']. Then fill that array with the states present in $states_of_the_USA.
for ($counter = 1; $counter < 51; $counter++) {
echo"<input type='hidden' name='hiddenstate[]' value='$
states_of_the_USA[$counter]'>";
}
After you've read across the names of 50 states, add a submit query button and close the form:
<input type="submit" value="Find Capital">
</form>
The PHP program now has two sets of data. The first is obtained from the drop-down list box, and contains the name of the single state that the user selected. It's stored in the variable $state. The second is a list of the 50 states, in alphabetical order, stored in the array $hiddenstate. (Because PHP populated this array, the index numbers run from 0 to 49. This isn't a problem; you just need to be aware of it. The first line deals with it.) Now create an array with the names of the 50 state capitals. To match the indexes of the $hiddenstate array, you need to make the array indexes run from 0 to 49:
$state_capital = array (0 => "Montgomery", "Juneau", "Phoenix", "Little Rock", "Sacramento", "Denver", "Hartford", "Dover", "Tallahasse", "Atlanta", "Honolulu", "Boise", "Springfield", "Indianapolis", "Des Moines", "Topeka", "Frankfort", "Baton Rouge", "Augusta", "Annapolis", "Boston", "Lansing", "Saint Paul", "Jackson", "Jefferson City", "Helena", "Lincoln", "Carson City", "Concord", "Trenton", "Santa Fe", "Albany", "Raleigh", "Bismarck", "Columbus", "Oklahoma City", "Salem", "Harrisburg", "Providence", "Columbia", "Pierre", "Nashville", "Austin", "Salt Lake City", "Montpelier", "Richmond", "Olympia", "Charleston", "Madison", "Cheyenne");
The $hiddenstate and $state_capital now arrays now correspond by index, which makes the rest of the program very straightforward. In fact you just need one loop, which runs from 0 to 49:
for ($counter=0; $counter<50; $counter++)
{
Inside you nest a conditional statement that checks to see if the current state is equal to the state that the user selected. If it is, you display the contents of the corresponding element of $state_capital, making use of the correspondence between the arrays:
if($_POST['hiddenstate'][$counter]==$_POST['state])
{
echo"The state capital of $_POST['state'] is
<b>$state_capital[$counter]</b><hr>";
}
}
If there isn't a match, continue iterating through the for loop until there is one. Using the list box, there is only a finite set of choices, so you know there will always be a match. That's all this program needs to do.
Improvements to the Program
The preceding program was not as easy as it could have been so that you could see how two separate arrays can be linked by an index number. If you actually wanted to run an example like it, it'd be much simpler to use an associative array, where you link the array items within one array statement like this:
$state_capital = array ("Alabama" => "Montgomery" "Alaska" => "Juneau"; "Phoenix" =>"Arizona", "Arkansas" => "Little Rock"; "California" => "Sacramento", "Colorado" => "Denver", "Connecticut" => "Hartford", "Delaware" => "Dover", "Florida" => "Tallahasse", "Georgia" => "Atlanta", "Hawaii" => "Honolulu", "Idaho" => "Boise", "Illinois" => "Springfield", "Indiana" => "Indianapolis", "Iowa" => "Des Moines", "Kansas" => "Topeka", "Kentucky" => "Frankfort", "Louisiana" => "Baton Rouge","Maine" => "Augusta", "Maryland" => "Annapolis", "Massachusetts" => "Boston", "Michigan" => "Lansing", "Minnesota" => "Saint Paul", "Mississippi" => "Jackson", "Missouri" => "Jefferson City", "Montana" => "Helena", "Nebraska" => "Lincoln", "Nevada" => "Carson City", "New Hampshire" => "Concord", "New Jersey" => "Trenton", "New Mexico" => "Santa Fe", "New York" => "Albany", "North Carolina" => "Raleigh", "North Dakota" => "Bismarck", "Ohio" => "Columbus", "Oklahoma" => "Oklahoma City", "Oregon" => "Salem", "Pennsylvania" => "Harrisburg", "Rhode Island" => "Providence", "South Carolina" => "Columbia", "South Dakota" =>"Pierre", "Tennessee" => "Nashville", "Texas" => "Austin", "Utah" => "Salt Lake City", Vermont" => "Montpelier", "Virginia" => "Richmond", "Washington" => "Olympia", "West Virginia" => "Charleston"; "Wisconsin" => "Madison", "Wyoming" => "Cheyenne");
Then you could output the capital using the state name variable, $state, as the index.
Iterating Through Non-Sequential Arrays
It's pretty simple to iterate through arrays whose elements have been populated sequentially (first element populated first, second element second, third element third, and so on). But is it that simple if the elements weren't populated sequentially? For example:
$array[56993]="absolutely huge";
$array[1]="quite small";
$array[499]="quite big";
Actually, non-sequential arrays aren't that much of a problem, and your old methods still work. It doesn't matter to PHP if you store the values out of order because it considers them to be in the straightforward numerical order of the index values. The only problem is that when you check through all of the elements sequentially, you might find yourself checking a lot of empty space in a large array like this example, which contains only three values!
current() and key() Functions
PHP uses a pointer to keep track of which element it's at when it moves through an array. The pointer indicates the element that is currently being used by the script. You can use the current() function to view the value of that element, and you can use the key() function to find out its index value. (Key is another name for index.)
Here's a little code snippet to illustrate how current() and key() work. When you first open a PHP script with this code in it, you might wonder which index PHP first looks at first.
$director[4]="Orson Welles";
$director[1]="Carol Reed";
$director[93]="Fritz Lang";
$director[24]="Jacques Tourneur";
You can find out by adding the next couple of lines, which return the current index of $Director[], and echo it:
$current_index_value = key($director);
echo ($current_index_value);
The key() function returns the value 4. Why? Because it returns the index value of the first item you placed into the array (when your script first runs, the first element you entered is the current element), which was Orson Welles at index 4 (the key produced by the key() function). If you use the current() function, it returns the value Orson Welles (the value of the current element produced by the current() function):
$current_contents = current($director);
echo ($current_contents);
Now, if you then added the following line to the array:
Alfred Hitchcock would be placed in the array at the index value 94, not zero, because to PHP, the lowest value in the set of index numbers being used is 93, and the next unfilled element is numbered 94. How can you test to find out what the index value of the new element is, given that the key() and current() functions return information on the first item to be placed in the array? Read on.
next() and prev() Functions
To find out the index value of a new element added to an array, you use the next() and prev() functions. These functions enable you to navigate through arrays by moving the pointer to the next or previous element in the array. They both take the name of the array to navigate through as an argument. For example, in the preceding array creation list:
$director[4]="Orson Welles";
$director[1]="Carol Reed";
$director[93]="Fritz Lang";
$director[24]="Jacques Tourneur";
$director[]="Alfred Hitchcock";
You call the next() function before checking the current index, and the contents of the current element:
next($director);
$current_index_value = key($director);
echo ($current_index_value);
The value displayed is 1, and the current() function returns the name Carol Reed.
If you call next() three more times:
next($director);
next($director);
next($director);
next($director);
$current_index_value = key($director);
echo ($current_index_value);
The value 94 is displayed. If you now call the current() function:
$current_contents = current($director);
echo ($current_contents);
The browser displays Alfred Hitchcock.
The prev() function is used in a similar way. Take the preceding example and add one occurrence of prev() after the four of next():
next($director); next($director); next($director); next($director); prev($director); $current_index_value = key($director); echo ($current_index_value);
You'll see 24, which is the index value associated with Jacques Tourneur, because you've moved forward through four items of the array and back through one. This is fairly straightforward, although one question that springs to mind is: what happens when you move next() beyond the last item in the array, or prev() before the first?
prev($director);
$current_index_value = key($director);
echo ($current_index_value);
The answer is: nothing at all. The code snippet would return no value. It won't generate an error (as it would in some programming languages); the pointer just moves beyond the end of the array. However, you wouldn't be able to move it back again:
prev($director);
next($director);
next($director);
$current_index_value = key($director);
echo ($current_index_value);
This would still return nothing at all.
So, you can see that the order in which you choose to populate the array makes no difference to the order in which they'll be navigated. Any new value placed in the array is placed in the element immediately above the filled element with the highest index. So if the highest filled element had index 34, the next value would be placed in index 35.
Just remember: to navigate through the arrays, use the next() and prev() functions, and to display the current position (the element the pointer is currently pointing to), use the current() and key() functions.
list() and each() Functions
If you're iterating through a non-sequential array, you can make life easier for yourself. Rather than looping through loads of empty values, you can use the list() and each() functions to return only the elements in the array that contain data. This enables you to display the entire contents of an array with the minimum amount of fuss. You use the while loop to perform this task for you, like this:
while (list(IndexValue, ElementContents) = each(ArrayName))
This says: for each element of the array Arrayname, set IndexValue equal to the element's index, and ElementContents equal to the contents of the element. If you only want to return either the index or the contents, then you can just omit the appropriate attribute:
while (list(IndexValue) = each(ArrayName))
Or:
For the Directors code snippet you could write the following code to display the name of each director in the array:
while (list($element_index_value, $element_contents) = each($director)){
echo "<br>$element_index_value - $element_contents";
}
You don't have to call the variables $element_index_value and $element_contents; that's just been done here for clarity's sake. You could just as easily have called them:
while (list($MickeyMouse, $DonaldDuck) = each ($Director)){
echo "<BR>$MickeyMouse - $DonaldDuck";
}
Either way, the result would be as follows:
4 - Orson Welles
1 - Carol Reed
93 - Fritz Lang
24 - Jacques Tourneur
94 - Alfred Hitchcock
All you've got to remember is that list() returns the index value first and the element contents second. That provides you with some useful tools, which are applicable even if the array doesn't happen to have numerical index.
Iterating Through String-Indexed Arrays
The rules for navigating through associative arrays are similar to those for numerically indexed ones, but there are some slight differences. The first difference is that the following lines, which would have worked fine if the array were numerically indexed, will now create a numerically indexed array:
$state_capital["GA"]="Atlanta";
$state_capital["IL"]="Springfield";
$state_capital["CA"]="Sacramento";
$state_capital[] = "Cheyenne";
The value Cheyenne will be stored in the array item $state_capital[0]. It's not too surprising, given that PHP has no idea what you want to create as an index value, which might be WY, but it might just have easily been AB or 4563, so instead it just tries to find the biggest numerical index. Because you haven't added a numerical index, PHP starts at the beginning with zero.
The current() and key() functions will still work in the way you expect on associative arrays. If you try the following code:
$what_state = current($state_capital); $what_abbreviation = key($state_capital); echo"$what_abbreviation - $what_state";
You'll find that it returns the first element to be filled in the array, which was index GA containing Atlanta. And you can also iterate through each list as before:
$state_capital["GA"]="Atlanta";
$state_capital["IL"]="Springfield";
$state_capital["CA"]="Sacramento";
$state_capital[] = "Cheyenne";
next($$state_capital);
$what_state = current($state_capital);
$what_abbreviation = key($state_capital);
echo "$what_abbreviation - $what_state";
This time you display the result IL - Springfield. The functions list() and each() also function the same way. You can set up the following array:
$state_capital = array ("GA" => "Atlanta", "IL" => "Springfield",
"CA" => "Sacramento", "WY" => "Cheyenne");
Then you can feed the array to the each function, and use list() to display the contents as before:
while (list($state_abbreviation, $state_name) = each ($state_capital)){
echo "<br>$state_abbreviation - $state_name";
}
This produces the list of abbreviations and state names as expected, and displays them in the order you created them:
GA - Atlanta
IL - Springfield
CA - Sacramento
WY - Cheyenne
What happens, though, if you want PHP to create or preserve a different order? Keep reading.
Sorting Arrays
There are several functions that PHP provides for sorting arrays, and you'll explore the five most commonly used: sort(), asort(), rsort(), arsort(), and ksort(). They all work in conjunction with the list() and each() functions that you just examined.
The sort() Function
sort() is the most basic of the sorting functions. It takes the contents of the array and sorts them into alphabetical order. The function requires only an array name to sort the array:
sort(ArrayName)
If you create an array of directors using the array structure:
You can sort the elements by supplying the array name to the sort() function as follows:
sort($director);
To view the effect this function has had on the array, you can use the list() and each() functions again. As previously stated, the order in which items are stored in the array is the order in which they were created in the array. With this directors array you'd expect the following order:
$Director[0]= "Orson Welles"
$Director[1]= "Carol Reed"
$Director[2]= "Fritz Lang"
$Director[3]= "Jacques Tourneur"
After using sort(), though, a different pattern emerges, as the sort() function resorts in alphabetic order, and then rebuilds the index numbers to match the new alphabetic order, as shown here:
$Director[0]= "Carol Reed"
$Director[1]= "Fritz Lang"
$Director[2]= "Jacques Tourneur"
$Director[3]= "Orson Welles"
You can check this, using the earlier code snippet to display the contents of the list on the screen:
while (list($IndexValue, $DirectorName) = each ($Director)){
echo "<BR>$IndexValue - $DirectorName";
}
The asort() Function
The function asort() takes arrays created with a string index and sorts them according to their contents. You are probably asking, "Isn't this just what sort did?" Not quite. The assort() function leaves the index numbers or element names intact, instead of rebuilding them like the sort() function did. Recall the state capitals code snippet:
$state_capital = array ("GA" => "Atlanta", "IL" => "Springfield",
"CA" => "Sacramento", "WY" => "Cheyenne");
You'd expect the array to be created as follows:
$state_capital["GA"]= "Atlanta"
$state_capital["IL"]= "Springfield"
$state_capital["CA"]= "Sacramento"
$state_capital["WY"]= "Cheyenne"
If you perform a sort on it:
sort($state_capital);
You get the following order:
$state_capital[0]= "Atlanta" $state_capital[1]= "Cheyenne" $state_capital[2]= "Sacramento" $state_capital[3]= "Springfield"
In other words, the string index values are replaced by numerical indexes—not particularly useful. However, if you call the asort() function:
asort($state_capital);
The order would be:
$state_capital["GA"]= "Atlanta"
$state_capital["WY"]= "Cheyenne"
$state_capital["IL"]= "Sacramento"
$state_capital["CA"]= "Springfield"
This time, the elements have been sorted alphabetically, and the string indexes have been retained. Again, you can use list() and each() to show that this has been the case:
while (list($state_abbreviation, $state_name) = each ($state_capital)){
echo "<br>$state_abbreviation - $state_name";
}
The rsort() and arsort() Functions
The functions rsort() and arsort() work in a similar way to their close relations sort() and asort(). The only difference is that they return the array elements in reverse alphabetical order. You can use rsort() to reverse the list of directors:
$director = array ("Orson Welles", "Carol Reed", "Fritz Lang", "Jacques Tourneur");
rsort($director);
You can call arsort() to reverse the list of state capitals:
$state_capital = array ("ga" => "Atlanta", "il" => "Springfield",
"ca" => "Sacramento", "wy" => "Cheyenne");
arsort($state_capital);
You should be able to work out what the results are. If you want to check, adapt the code from the preceding sections to display the answers. These functions are useful if you need to sort in descending order rather than ascending order.
The ksort() Function
The ksort() function sorts the contents of an associative array according to the index. It's applied in exactly the same way as the other sort functions, but it arranges an associative array in alphabetical order of string indexes. It's useful to be able to sort by the index numbers or element names when you are manipulating data by them instead of by the actual values. In the state capitals example, for instance:
$state_capital = array ("ga" => "Atlanta", "il" => "Springfield", "ca" => "Sacramento", "wy" => "Cheyenne"); ksort($state_capital);
ksort() would yield the following order:
$state_capital["ca"]= "Sacramento"
$state_capital["ga"]= "Atlanta"
$state_capital["il"]= "Springfield"
$state_capital["wy"]= "Cheyenne"
So if you happen to be using the state abbreviations instead of the state names for some purpose, you can still perform a sort.
Multidimensional Arrays
It is possible to create an array of arrays. Such beasts are known as multidimensional arrays. They are useful when representing data that needs two sets of indexes, such as coordinates on a map or graph. You can carry on nesting arrays in a multidimensional array until PHP runs out of memory, which would probably be in under 100 nested arrays. (If you can think of a sensible practical use of any more than 10 nested arrays, then you deserve a medal.) Multidimensional arrays are set up in the same way as normal arrays, except that you call the array structure as an argument to itself, like this:
ArrayName = array (index => array (Array contents))
An example might be an array in which each element represents one member from a group of people, and each element is also an array, used to store the details for each person:
$phone_directory = array ("John Doe" => array ("1 Long Firs Drive",
"777-000-000"), "Jane Doe" => array ("4 8th and East", "777-111-111"));
This array now has entries for John Doe and Jane Doe; and each element represents an array with two entries, one for an address and one for a phone number. To actually get hold of this information, you have to use a nested loop to get it:
$phone_directory = array ("John Doe" => array("1 Long Firs Drive",
"777-000-000"),
"Jane Doe" => array("4 8th and East", "777-111-111"));
while (list($person) = each($phone_directory)){
echo("<br>$person");
while (list(,$personal_details) = each ($phone_directory[$person])) {
echo (" $personal_details");
}
}
The <br> tag and the space before $personal_details in the echo statement are simply used to make the displayed details more presentable. Multidimensional arrays aren't encountered very often, so they won't be discussed any more here, although you're now aware of them.
Practical Demonstration of Arrays
This chapter's covered a lot of material, so instead of an extensive example at the end, you'll just deal with a short one—but it includes many of the features you just learned about. So take a deep breath and charge right in.
Try it out: Combine Array Features in a Practical Example
This example takes a set of mythical students and asks for the grades they got on their Math exam. Among other things, you'll sort them into grade order (A is highest, F is lowest) on the Web page. Some <table> tags are included to make everything more presentable.
-
Prod your Web page editor into life, and type in the following:
<html> <head><title></title></head> <body> <form method="POST" action="exam.php"> <input type="hidden" name="posted" value="true"> <table border="1"> ?php $student = array("Albert Einstein", "Ivan the Terrible", "Napoleon", "Simon Bolivar","Isaac.Newton"); while (list(, $name) = each($student)) { echo "<tr><td>What grade did <b>$name</b> get in math?</td>"; echo"<td><select name='math[]'> <option>grade A</option> <option>grade B</option> <option>grade C</option> <option>grade D</option> <option>grade F</option> </select>"; echo"<input type='hidden' name= 'student[]' value='$name'></td>"; } ?> </tr> <tr><td> </td><td> <input type="submit" value="Get Grades"> </td></tr> </form> </table> <?php if (isset($_POST['posted' ])) { ?> <hr> <table border="1"> <tr><td colspan="2"> In math the grades were in order: </td></tr> <?php while (list($index, $value}=each($_POST['math'])) { $gradestudent[]=$_POST['math'][$index].$_POST('student'][$index]; } asort($gradestudent); while (list($index,$value)=each($gradestudent)) { $student_index = $_POST['student'][$index]; $math_index = $_POST['math'][$index] ; echo "<tr><td><b>$student_index</b></td><td>$math_index</td></tr>"; } } ?> </table> </body> </html>
-
Save file as exam.php and close it.
-
-
Click the Get Grades button and the grades are sorted, not only in order of grade, but also in alphabetical order of students' names where two or more students have the same grade.
How it Works
This little program had a difficult conundrum to sort out that you may have spotted. You need to sort the grades array, which corresponds by index to the student array. But how can you relate the sorted array of grades back to the array of students? Without too much difficulty, as it turns out, although it calls for a bit of sleight of hand.
The program creates a dynamically created form that supplies the names of the students from an array called $student:
<form method="POST" action="exam.php">
<input type="hidden" name="posted" value="true">
<table border="1">
<?php
$student = array("Albert Einstein","Ivan the Terrible", "Napoleon", "Simon
Bolivar","Isaac Newton");
A while loop is constructed to iterate through the contents of the student array. Because you only want the names and not the indexes in the student array, you ask list() to return only the names:
while (list(,$name) = each($student))
{
For each student in the list, you display a question asking for that student's grade:
Then you create a drop-down list box that contains five options, each corresponding to a grade from A to F. To store the grades, you create an array $math that PHP can pass to the next script:
echo"<td><select name='math[]'>
<option>grade A</option>
<option>grade B</option>
<option>grade C</option>
<option>grade D</option>
<option>grade F</option>
</select>";
You pass the values across to the second part of the script via a hidden HTML control that has the same name as the array which holds the students' names. Indicate that the control needs to be an array by adding brackets. Pass the control names for each student, and then end the loop:
echo"<input type='hidden' name='student[]' value='$name'></td>";
}
At the end of the loop add a Submit button and close the form:
?>
</tr>
<tr><td> </td><td>
<input type="submit" value="Get Grades">
</td></tr>
</form>
</table>
The second part of the program receives the form data. It's composed of a loop, a sort, and another loop.
The first loop is used to associate the two arrays received from the form. You do this by concatenating the grade to the student's name, and storing the result in a new array called $gradestudent:
<hr>
<table border="1">
<tr><td colspan="2">
In math the grades were in order:
</td></tr>
<?php
while (list($index,$value)=each($_POST['math']))
{
$gradestudent[]=$_POST['math'][$index].$_POST['student'][$index];
}
You know from examining the first script that the contents of an index in the $math array relate to the contents of the same index in the $student array. So this concatenation is a valid way of combining the related values from each array. The resulting $gradestudent array contains this:
Grade CAlbert Einstein Grade FIvan The Terrible Grade BNapoleon Grade DSimon Bolivar Grade AIsaac Newton
Now sort $gradestudent and you should get the order you want:
asort($gradestudent);
You are still left with the problem of how to display the results, which look a little unsightly in the format displayed before the sort. You can print out a sorted list of grades side-by-side with the students' names using the following snippet of code:
while (list($index,$value)=each($gradestudent))
{
echo
"<tr><td><b>$_POST['student'][$index]</b></td><td>$_POST[math][$index]</td>
</tr>";
}
}
?>
</table>
Can you see how this works? Remember that the $gradestudent array is sorted on grade. During the sort, the order of the elements was rearranged, but each index still contains the same content as before the sort. Each element in the $gradestudent array is simply a concatenation of the corresponding elements in the $math and $student arrays. So, what happens if you echo out elements from the $_POST['math'] and $_POST['student'] arrays, but in the order that the indexes occur in sorted $gradestudent? Because the indexes of all of these arrays correspond, you find that the $math and $student arrays are echoed out in grade order, too, as the table shows:
$Index | $Student | $Math | Sorted $GradeStudent |
|---|---|---|---|
4 | Isaac Newton | Grade A | "Grade AIsaac Newton" |
2 | Napoleon | Grade B | "Grade BNapoleon" |
0 | Albert Einstein | Grade C | "Grade CAlbert Einstein" |
3 | Simon Bolivar | Grade D | "Grade DSimon Bolivar" |
1 | Ivan The Terrible | Grade F | "Grade FIvan The Terrible" |
You know that using list() and each() provides index values from the sorted $gradestudent array in the order that they occur in the array, so the code snippet echoes out elements from the $_POST['math'] and $_POST['student'] arrays in grade order, too. And that's it.
The array_multisort() Function
The array_multisort() function sorts multiple arrays or a multidimensional arrays. It takes arrays as arguments. When sorting multiple arrays, the function sorts the first array and notes the indexes of any repeated entries in the array. It then sorts the repeated entries according to the contents of the corresponding indexes in the second array. Finally, the function sorts the second array into the same order as the sorted first array. Take a look at the preceding example. You could change the code in exam.php to use array_multisort():
<?php
array_multisort($math,$student);
while (list($index,$value)=each($student))
{
echo "<br>$student[$index] - $math[$index]";
}
?>
Now consider what would happen if this function was asked to sort the following year's math grades (stored in the $math array) for these students (whose names are stored in the $student array):
Albert Einstein - Grade A
Ivan The Terrible Grade F
Napoleon Grade D
Simon Bolivar Grade D
Isaac Newton Grade A
The array_multisort() function first sorts the $math[] array, giving A, A, D, D, F. Because there are two entries for each of A and D, the function notes the indexes of the two A entries (0 and 4), turns to the second array $student[] and sub-sorts elements 0 (Albert Einstein) and 4 (Isaac Newton) alphabetically by name. The same is done for the two D entries. When the function is finished sub-sorting, it notes the final index order of the $math array (0, 4, 2, 3,1), and sorts $student[] into the same order. Both arrays are now sorted primarily by grade and secondly by name.
foreach Loops
There's an extension to the for loop known as the foreach loop, that you use when you have an array with an unknown number of elements. It iterates until the end of the array. The loop has two formats. The first is as follows:
foreach ($ArrayName As $ArrayItem){
execute the contents of these braces;
}
This means that for each item in the array, you'll iterate around the loop. An example of this would be the crowd attendance at a baseball game. You might want to store the name of each fan in the baseball stadium in a database. But until the day of the game, you don't know how many fans will actually turn up. In pseudo code the example would look like this:
foreach ($crowd As $fan){
Add $fan to database...
}
It would go through the crowd adding a fan at a time. PHP doesn't need to be told how many fans attended the game because it can work this out from the number of items in the array $crowd.
The second format is:
This is the same as the first format, but it makes the array index value available as well. Take a quick look at how foreach works in the context of an example.
Try it Out: Use foreach
This example uses the list of states and displays each state in the array, along with the index value that PHP has assigned to the state.
-
Start your Web page editor and type in the following code:
<html> <head><title></title></head> <body> <? $states_of_the_USA = array ("Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"); foreach($states_of_the_USA as $state__index => $state) { echo "<br>$state_index - $state"; } ?> </body> </html>
-
Save this file as foreach.php. and close it.
-
Open the file in your browser, and scroll down just to check that all 50 states are there, with values running from 0 to 49.
How it Works
This couldn't be simpler. You first create the array with the names of all 50 states, which is called $states_of_the_USA:
$states_of_the_USA = array ("Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming");
Then supply the array name as the first argument to the foreach loop:
foreach ($states_of_the_USA As $state_index => $state){
The second and third arguments are variable names that you create yourself that hold the index value and the corresponding element in the array, respectively. You execute the contents of the braces for each of the 50 members in the array:
echo "<br>$state_index - $state";
}
This has the effect of displaying each index value and each state in the array on a separate line.
There are two points to note here. First, the current array element and array index are available as separate variables. Because each iteration processes a new array element, each time you go around the loop the variables are effectively assigned a new value.
And second, you haven't supplied a count of how many elements there are in the array anywhere in the program. PHP has worked this out for itself, and that's the main advantage of using a foreach loop. This factor enables you to iterate through an array that might not be in any numerical or alphabetical order. There might also be missing entries in the array, but it doesn't have to check every index value, only the elements that contain values. You could include the following code, which adds a new element to the array of states:
$states_of_the_USA[100]="Atlantis";
Then if you reperformed the foreach loop, it would be able to add this value to the end of the Web page without needing to check through elements 50-99.
