PhpRiot
News Archive
PhpRiot Newsletter
Your Email Address:

More information

Better Object-Oriented Arrays

Note: This article was originally published at Planet PHP on 18 April 3200.
Planet PHP

I've been working on developer-facing software and SDKs in PHP for nearly a decade, and through the experience of supporting these developers, I've learned something interesting about the PHP community at-large. The majority of PHP developers have a very good understanding of native types (e.g., strings, arrays, integers, booleans). Since they're the lowest common denominators of the PHP language, it's generally pretty easy for developers to understand these types.

But the moment you introduce concepts like objects as return types, people suddenly can't figure out how the darn thing works. It's remarkably similar to when people forget how to drive the instant it starts raining. Most PHP software has trained us to expect native types as responses, but if you return something like a `SimpleXMLElement` object or some other sort of custom object, confusion erupts!

Stopping the Insanity with Collections

In an effort to find a better solution to the array versus object debacle, I started investigating the possibility of object-oriented arrays in PHP. This way, you can return an array-like object which behaves just like you'd expect an array to, but has all of the power of an object.

PHP has two classes called ArrayObject and ArrayIterator that are more like stubs than anything useful. What they provide, however, is a reasonably solid foundation for building a useful object-oriented array class on top of. These classes also implement a set of interfaces that give us a significant amount of functionality relatively for free.

Since the word array already has a specific meaning in PHP, I'll call our new object-oriented array class the Collection class. The goal of this class is to behave identically to an array, but support a variety of methods like the kind you'd find in everything-is-an-object languages like Ruby and JavaScript.

Constructor

Let's begin with our class definition and constructor:

class Collection implements IteratorAggregate, ArrayAccess, Countable, Serializable { private $collection; private $iterator; public function __construct($value = array()) { $this-collection = new ArrayObject($value, ArrayObject::ARRAY_AS_PROPS); $this-iterator = $this-collection-getIterator(); } }

Note: The IteratorAggregate interface extends the Traversable interface, which enables foreaching through the collection.

Interface Methods

Next, we need to implement all of the methods that are defined by the interfaces. These include:

  • current, key, next, rewind, seek, and valid from the Traversable interface.
  • getIterator from the IteratorAggregate interface.
  • offsetExists, offsetGet, offsetSet, and offsetUnset from the ArrayAccess interface.
  • count from the Countable interface.
  • serialize and unserialize from the Serializable interface.

For the most part, these can be implemented by simply calling out to the already-existing methods on the $this-collection and $this-iterator properties.

If you want your collections to be able to be serialized and unserialized, you'll need to custom implement these methods. The trickiest thing to watch out for is handling cases where your collection contains a SimpleXMLElement element. Since SimpleXMLElement can't be serialized, you'll need to manually convert the object to an XML string on serialization, and re-parse it on unserialization.

Converting Types

So far, you'll already be able to do things like this:

$data = new Collection(array(1, 2, 3, 4, 5, 'a', 'b', 'c')); $numbers = new Collection(); $letters = new Collection(); foreach ($data as $entry) { if (is_int($entry)) { $numbers[] = $entry; } elseif (is_string($entry)) { $letters[] = $entry; } }

However, since array functions in PHP require the inputs to be real arrays, we'll need to be able to easily export the collection to an old-school array.

public function to_array() { return $this-collection-getArrayCopy(); }

Maybe you even want to add functionality to implement things like to_json(), to_yaml(), or to_object(). This is really easy to do with off-the-shelf tools found in PHP itself and popular third-party packages (such as Symfo

Truncated by Planet PHP, read more at the original (another 4851 bytes)