Exploring SPL: Part II
Implementing ArrayAccess

In this installment, we will be exploring one of SPL's frequently used interfaces, the ArrayAccess interface. By implementing this interface, a class can allow its objects to be accessed as if they were arrays. This approach is particularly useful for setting up accessor methods for a class (getters and setters), though it can be used for almost any purpose. Let's dig a little deeper...
ArrayAccess defines just four methods that must be implemented. It is important to understand that these methods are not usually called directly. Instead they are triggered when particular actions are taken on a given object normally reserved only for arrays.
class Email implements ArrayAccess {
protected $_to;
protected $_from;
protected $_subject;
protected $_message;
public function offsetExists($offset) {
return isset($this->_$offset)
}
public function offsetGet($offset) {
return $this->_$offset;
}
public function offsetSet($offset, $value) {
$this->_$offset = $value;
}
public function offsetUnset($offset) {
unset($this->_$offset);
}
public function print() {
echo '<pre>';
echo 'To: ' . $this->_to . "\n";
echo 'From: ' . $this->_from . "\n";
echo 'Subject: ' . $this->_subject . "\n";
echo 'Message: ' . "\n" . $this->_message;
echo '</pre>';
}
}
Here we have a basic Email class that stores some information about an email message. It is generally considered good practice for class member variables to be protected or private so that code outside the class cannot access or change their values without the class knowing about it. One way to provide access to these values without breaking the concept of data encapsulation is by implementing the ArrayAccess interface and using its methods to store and retrieve their values.
To see how everything works, we have also added an additional print() method to display the contents of an Email object. Below is a quick sample script that makes use of the class we just created:
// Create a new Email instance.
$email = new Email();
// Assign values to it like an array.
$email['to'] = 'me@myselfandi.com';
$email['from'] = 'you@yourselfandyou.com';
$email['subject'] = 'A Test Message';
$email['message'] = 'This is your favorite Email class, '
. 'just sending a quick hello to the world!';
// Display the email message's contents.
$email->print();
As you can see, we can now access an Email object like an array, using keys to specify what value we want to set or retrieve. When we utilized the syntax for specifying array keys on our Email object, an implicit call was made to offsetSet() to apply the value. If we had simply retrieved a value by specifying an array index, we would have instead triggered a call to offsetGet(). The two remaining methods, offsetExists() and offsetUnset() are both triggered by functions like isset() and unset() respectively.
Now that the basics are covered, let's add some checks to make sure only the 4 properties can be set this way and add a send() method that will actually send off our email message.
class Email implements ArrayAccess {
protected $_to;
protected $_from;
protected $_subject;
protected $_message;
public function offsetExists($offset) {
return isset($this->_$offset) && ('to' || 'from' || 'subject' || 'message');
}
public function offsetGet($offset) {
if($offset == ('to' || 'from' || 'subject' || 'message')) {
return $this->_$offset;
}
else {
throw new Exception('Invalid offset "' . $offset . '" specified.')
}
}
public function offsetSet($offset, $value) {
if($offset == ('to' || 'from' || 'subject' || 'message')) {
$this->_$offset = $value;
}
else {
throw new Exception('Invalid offset "' . $offset . '" specified.')
}
}
public function offsetUnset($offset) {
unset($this->_$offset);
}
public function print() {
echo '<pre>';
echo 'To: ' . $this->_to . "\n";
echo 'From: ' . $this->_from . "\n";
echo 'Subject: ' . $this->_subject . "\n";
echo 'Message: ' . "\n" . $this->_message;
echo '</pre>';
}
public function send() {
return mail($this->_to, $this->_subject, $this->message, 'From: ' . $this->_from);
}
}
And now we give our class one final test run, using our added send() method:
// Create a new Email instance.
$email = new Email();
// Assign values to it like an array.
$email['to'] = 'me@myselfandi.com';
$email['from'] = 'you@yourselfandyou.com';
$email['subject'] = 'A Test Message';
$email['message'] = 'This is your favorite Email class, '
. 'just sending a quick hello to the world!';
// Send the email message.
$email->send();
After creating a new Email object, we took advantage of the fact that it implements the ArrayAccess interface and assigned its properties using array keys. After that, a quick call to $email->send() sent the message on its way.



Awesome! :) Thanks!
Left by jj | Nov. 6, 2009 at 1:38am
Leave a Comment