jwallace.us

tech, tunes, and other stuff

Accessing Objects as Arrays in PHP

As I was studying the PHP SPL I came across the ArrayAccess class. I wondered what use it could possibly be since PHP’s array functionality is quite rich. So, I sent an email off to Lorna Jane, whom I met at this year’s PHP Community Conference held here in Nashville back in April. She gave me a very good explanation, so I decided to work up an example to cement the knowledge in my brain.

Since an example is worth a 1000 wordy descriptions, here is my Fruity example below.

First we need a basic object to describe a Fruit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# simple class to store a fruit string as a class property
class Fruit {
   private $name = NULL;
   private $info = NULL;

   function __construct ($fruit, $info) {
      $this->set_fruit ($fruit, $info);
   }

   function get_name () {
      return $this->name;
   }

   function get_info () {
      return $this->info;
   }

   function set_fruit ($name = "no name", $info = "no info") {
      $this->name = $name;
      $this->info = $info;
   }

   # a php "magic method" that allows a class to decide how
   # it will react when it is treated like a string
   public function __toString () {
      return ($this->get_name() . " is " . $this->get_info());
   }
}

Next we need a class that actually implements the ArrayAccess class that holds a collection of these Fruit objects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
require_once ("Fruit.php");
class FruitAccess implements ArrayAccess, Iterator {
   private $data = array();

   function __construct ($fruits) {
      $i = 0;

      foreach ($fruits as $key => $value) {
         $this->offsetSet ($key, new Fruit($key, $value));
         $i++;
      }
   }

   ####################   ArrayAccess methods  ####################

   function offsetSet ($offset, $value) {
      if (is_null($offset)) {
         throw new Exception ("Key cannot be NULL");
      }
      else {
         $this->data[$offset] = $value;
      }
   }

   function offsetGet ($offset) {
      return $this->data[$offset];
   }

   function offsetUnset ($offset) {
      unset ($this->data[$offset]);
   }

   function offsetExists ($offset) {
      return array_key_exists ($offset, $this->data);
   }

   ####################   Iterator methods  ####################

   public function rewind() {
     reset ($this->data);
   }

   public function current() {
     return current ($this->data);
   }

   public function key() {
     return key ($this->data);
   }

   public function next() {
     return next ($this->data);
   }

   public function valid() {
     return ($this->current() !== false);
   }

   ####################   FruitAccess methods  ####################

   public function count () {
     return count ($this->data);
   }
}

Finally we need a little program that demonstrates how it all works together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
require_once ("FruitAccess.php");

#  This example shows how to access objects as arrays using PHP's SPL

$fruit_array = array ("apple" => "crunchy", "orange" => "tangy",
                      "banana" => "yellow", "grape" => "small",
                      "cherry" => "red");
$fruit = new FruitAccess ($fruit_array);

echo PHP_EOL . "Access the objects as a traditional array..." . PHP_EOL;
foreach ($fruit as $key => $value) {
   echo $fruit["$key"] . PHP_EOL;
}

echo PHP_EOL . "...or use the Iterator implementation..." . PHP_EOL;
$fruit->rewind();
while ($fruit->valid()) {
   echo $fruit->current() . PHP_EOL;
   $fruit->next();
}

All this code, if run from the command line, will product the following output:

Access the objects as a traditional array...
apple is crunchy
orange is tangy
banana is yellow
grape is small
cherry is red

...or use the Iterator implementation...
apple is crunchy
orange is tangy
banana is yellow
grape is small
cherry is red

You can download the source used in this posting:  here