Associative Arrays

Main | Arrays | Practice 8 | Solution 8 | Associative Arrays | Practice 9 | Solution 9 | Regular Expressions | Practice 10 | Solution 10 | More Regular Expressions | Practice 11 | Solution 11

Associative Arrays Basics

So far we have studied arrays whose elements can be referenced through numbers. For example:

$home = array();
$home[0] = "couch";
$home[1] = "chair";
$home[2] = "table";
$home[3] = "stove";

The above could be expressed more cleanly (as the numeric indexes are implicit) as the following:

$home = array("couch", "chair", "table", "stove");

PHP also allows us to reference elements of an array with more meaningful indexes. The following array is an Associative Array:

$a = array();
$a["color"] = "red";
$a["taste"] = "sweet";
$a["shape"] = "round";
$a["name"] = "apple";

The above is the same as the following:

$a = array( 
	   "color" => "red", 
	   "taste" => "sweet", 
	   "shape" => "round", 
	   "name"  => "apple"
	  );

Note that PHP allows us to use some syntactic sugar with the => (equals sign, greater than sign) sequence.

When iterating over an associative array you can't use a loop that is based on numbers since the array indices are not numbers. Instead you can use the foreach language construct. To use the foreach statement to iterate over the above array, we would say the following:

foreach ($a as $key => $value) {
    print "Key is $key and Value is $value<br>";
}

One way to interpret the above loop is the following:

Each element in the array $a has a key which we will call $key which corresponds to a value which we will call $value.

So a foreach statement allows us to iterate over the values of an array and give those values meaningful names.

If we were to run the above loop on the above array $a we would see the following:

Key is color and Value is red
Key is taste and Value is sweet
Key is shape and Value is round
Key is name and Value is apple

You can also have associative arrays of associative arrays. There is practically no limit to the amount of levels you could have. Suppose that you wanted a way to associate the names of some characters from a book with the places that those characters lived. For example consider the following list of places and inhabitants of those places (in this case Tolkien's characters from The Lord of the Rings):

Hobbiton: Bilbo Frodo Samwise
Brandybuck: Meriadoc Pippen
Rivendell: Elrond Arwen
Lothlorien: Galadriel

In the above example we have an associative array of places, and each place maps to an array of people that live in those places. We could represent this in PHP with the following:

$homes = array (
                "Hobbiton" => array("Bilbo", "Frodo", "Samwise"),
		"Brandybuck" => array("Meriadoc", "Pippen"),
		"Rivendell" => array("Elrond", "Arwen"),
		"Lothlorien" => array("Galadriel")
		);
What if we wanted to print the above associative array of arrays so that it looked like the previous printout? We could use the following function:
function printout($ar) {
  foreach($ar as $place => $people) {
      print "<b>$place</b>: ";
      foreach($people as $person) {
	  print "$person ";
      }
      print "<br>\n";
  }
}

In the above example we have a loop that takes each $place in the array and maps to that place's array of $people. Withing that array of people we evaluate each $person contained in the inner array. Note that the inner array is not associative so we map to just $person as opposed to $person => $some_other_property. Note also that we choose to print at certain points in the code so that our list looks orderly like the one above.

Associative Arrays and Pull Down Menus

Coding HTML pull down menus like the following can be tedious:

Select a Campus:

The above code associates a campus that the user of the form can choose to map that campus to the correct person to be emailed regarding an issue.

The above type of HTML code can be expressed in the following general way:

<select name=campus>
<option value="some_value">value's first name
<option value="some_other_value">value's second name
...
<option value="final_value">value's last name
</select>

Since coding the above can be tedious (especially as the list grows) it is best to store the list of contact people in one array and then use a loop as in the following example to print a menu for an HTML form:

print "<select name=\"campus\">";
foreach($a as $person => $place) {
  print "<option value=\"$person\">$place\n";
}
print "</select>";

Recall from our discussion on PHP Forms that we established three states to online form presentation. We established that the during the second state that the user had left a part of the form incomplete and would be asked to fill in the left out field. Recall that we tried to make things easier for the user by taking advantage of HTML's value tag.

For example if we wanted someone to type their full name and we had some way of determining that they had only typed their first name we could have the field that represented their first name have the default value so that when the form reloaded their first name would be there so that they would not have to type it again. Such a form could look like this:

First Name:

and its code would be the following:

First Name:  
<input type=text name=first_name value="<?php print $first_name; ?>">

Doing the above makes things more convenient for the user regrading text boxes. We can do the same for our users by using the HTML tag selected. To take advantage of this tag consider the following variation of our code:

print "<select name=\"campus\">";
foreach($a as $person => $place) {
  if ($campus == $person) {
     print "<option value=\"$person\" selected>$place\n";
  }
  else {
     print "<option value=\"$person\">$place\n";
  }
}
print "</select>";

In the above example our form will not have any default selected value since the variable $campus will not be set and the else condition will be chosen in all of the above loops. After the form is submitted and the user has chosen a particular option for $campus that choice will be selected when choice comes up again in the above loop and the condition $campus == $person is true.

What if we wanted to expand the above code so that we didn't just associate one person with place but several? We would use a variation of the above code that took advantage of arrays within arrays. The following code does this:


<?php
function make_select_menu($ar, $default="") {
        foreach($ar as $place => $people) {
                $person_string = "";
                foreach($people as $person) {
                       $person_string .= "$person, ";
                }
                // strip off the last ", "
                $person_string = substr($person_string, 0, -2);

                if ($default == $person_string) {
                // this is done so that when the function is
                // is called a second time (due to user error)
                // the value that they picked will be selected 
                // by default
                    print "<option value=\"$person_string\" selected>$place\n";
                }
                else {
                    print "<option value=\"$person_string\">$place\n";
                }
        }
}

$contacts = array(
        "College Ave Campus" => array("jfulton [at] member.fsf.org",
                                        "jfulton@mssg.rutgers.edu"),
        "Cook/Douglass Campus" => array("jfulton1@rci.rutgers.edu",
                                        "jfulton1@mssg.rutgers.edu"),
        "Livingston Campus" => array("jfulton2@rci.rutgers.edu",
                                        "jfulton2@mssg.rutgers.edu"),
        "Busch" => array("jfulton3@rci.rutgers.edu", 
                                        "jfulton3@mssg.rutgers.edu")
        ); 

print "<p>Select a Campus: ";
print "<select name=\"campus\">";
make_select_menu($contacts, $campus);
print "</select>";
?>

In the above example the contacts array contains only variations of my email address. In a real application you would probably map each campus to a list of people who could be emailed when this form is submitted.

Variable variables

The PHP manual has a short section on variable variables. These types of variables can be useful given PHP's pre-defined associative arrays. Given the following code:
$x = "something";
$something = "y";

We can deduce the following relation which is valid in PHP:

$$x == "y";

When making PHP statements like the above, some prefer to make their code more readable by using curly braces ({ }):

${$x} == "y";

Remember, it is just like taking the value of a variable, and using that value as the name for another variable. Doing this can allow you to write some compact code. Consider the following which allows us to set values in arrays:

$a[$x] = $$x

The above is the same as saying any one of the following:

$a['something'] = $$x;
$a['something'] = $something;
$a['something'] = "y";

but saying

$a[$x] = $$x 

can be more convenient, especially if you are in a loop.

Suppose that you wanted to call the urlencode function on every variable that a user had input from your form. You could iterate through the reserved arrays $HTTP_GET_VARS or $HTTP_POST_VARS (depending on whether your form had used the GET or POST method) using PHP's tools for associative arrays and then call the function on each variable with the following code:

foreach($HTTP_GET_VARS as $key => $val) {
    ${$key} = urlencode($val);  
}

Note that in the above code I don't know the names of each variable, and I don't need to know the name of each variable either, since the variable variables take care of this for me.


jfulton [at] member.fsf.org
22 Aug 2013