Creating a PHP Collection Class
Posted: May 15, 2010
PHP has really been growing up lately. There are some really nice new things in the SPL (Standard PHP Library), including some nice new collection structures familiar to programmers from other languages. We’ve got heaps, stacks, and queues. There are also some interfaces you can implement to create your own collections with standard array-like behavior.
Let’s take a look at building out our own basic collection class. We can extend and subclass this thing later to make it even more useful.
class Collection implements IteratorAggregate, Countable
{
/** hold the colleciton of items in an array */
protected $_items = array();
/**
* Optionally accept an array of items to use for the collection, if provided
* @params array $items (optional)
*/
public function __construct($items = null)
{
if ($items !== null && is_array($items)) {
$this->_items = $items;
}
}
/**
* Function to satisfy the IteratorAggregate interface. Sets an
* ArrayIterator instance for the server list to allow this class to be
* iterable like an array.
*/
public function getIterator()
{
return new ArrayIterator($this->_items);
}
/**
* Function to satisfy the Countable interface, returns a count of the
* length of the collection
* @return int the collection length
*/
public function count()
{
return $this->length();
}
/**
* Function to add an item to the Collection, optionally specifying
* the key to access the item with. Returns the item passed in for
* continuing work.
* @param $item the object to add
* @param $key the accessor key (optional)
* @return mixed the item
*/
public function addItem($item, $key = null)
{
if($key !== null) {
$this->_items[$key] = $item;
} else {
$this->_items[] = $item;
}
return $item;
}
/**
* Remove an item from the Collection identified by it's key
* @param $key the identifying key of the item to remove
*/
public function removeItem($key)
{
if(isset($this->_items[$key])) {
unset($this->_items[$key]);
} else {
throw new Exception("Invalid key $key specified.");
}
}
/**
* Retrieve an item from the collection as identified by its key
* @param $key the identifying key of the item to remove
* @return item identified by the key
*/
public function getItem($key)
{
if(isset($this->_items[$key])) {
return $this->_items[$key];
} else {
throw new Exception("Invalid key $key specified.");
}
}
/**
* Function to return the entire list of servers as an array
* of Server objects
* @return array
*/
public function getAll()
{
return $this->_items;
}
/**
* Return the list of keys to all objects in the collection
* @return array an array of items
*/
public function keys()
{
return array_keys($this->_items);
}
/**
* Return the length of the collection of items
* @return int the size of the collection
*/
public function length()
{
return count($this->_items);
}
/**
* Check if an item with the identified key exists in the Collection
* @param $key the key of the item to check
* @return bool if the item is in the Collection
*/
public function exists($key)
{
return (isset($this->_items[$key]));
}
}
This is fairly basic, but it’s already got some pretty useful stuff. We can add, remove, and retrieve items in this collection, as you’d expect. We can check to see if an item exists. Also, notice that we’re returning the object in question when we add it, so we can support some handy command chainging functionality. But we’ve got some other nifty features as well.
This Collection is iterrable (not irritable, it’s not grumpy). So you can just cycle over the whole thing in a foreach loop, just like an array. It does this by implementing the IteratorAggregate interface, which requires a function getIterator() to return an iterator object. The iterator it returns is just the array iterator created from the protected items array.
We’re also countable, by implementing the Countable interface. It requires one function count() which we just pass along to our length() function which returns the count of the items in our collection. Why have length()? Why not just return a count of our array in the count() method? So we can get the number of items two ways, either by count($collection) or $collection->length(). We like flexibility.
We also have some nice functions, getAll(), keys() which let us get the entire collection as an array (in case we absolutely need an array for something we’re working with), and to return a list of all the object keys in the array.
We can stuff just about anything we want in this collection, ints, strings, objects, and more. And it’s got some built-in behaviors that we’re used to seeing from arrays. But why go through all this trouble? Why not just use an array and call it a day?
Because this puppy’s extendable through the magic of Object-Oriented Inheritance!
I can easily add a method to this Collection class or a sub-class to support some specialized behavior. Say I created a subclass AggregateCollection that had a method that cycles through and gets an aggregate total of some certain property of every item in the collection:
public function getAggregateProperty($property)
{
$total = 0;
if (count($this) > 0){
foreach ($this->_items as $item) {
if ($item instanceof AggregateCollection) {
$total += $item->getAggregateProperty($property);
} else {
if ($item->$property !== null) {
$total += $item->$property;
}
}
}
}
return $total;
}
What’s this doing? We’re looping through the entire set of objects we have and aggregating the total of whatever property we passed in. Not only that, but we can even have a collection of collections, so we check to see if the child we have is a collection, and then call its method to get the aggregate properties of its items. This will extend as far down the chain as we need, so we can have an extensive hierarchial relationship of items, and with one method call:
$total = $collection->getAggregateProperty('someProperty');
And we don’t even need to know how far down the rabbit hole we need to go to get it.
Another thing I find pretty helpful, especially in light of how I like to chain commands, is a method something like this:
public function getOrMakeChild($id, $type, $params = null)
{
if ($this->exists($id)) {
return $this->getItem($id);
} else {
$child = new $type($params);
return $this->addItem($child, $id);
}
}
You can then in one call first check to see if an item exists by key, and if so, return the item to begin working with. If it doesn’t exist, it creates a new object based on the type you give it, then returns it. This can be any type of object that takes either zero or one parameter which you can optionally pass in with the call.
As you can see, you can build out your collection objects to do almost anything you need, making these a flexible, powerful alternative to arrays.

Hi,do you maybe have an php file examples,because i have an assignment i have to do using collection classes with a student object and calculating averages etc.
thanks
Hey! I know this is kinda off topic but I was wondering which blog platform are you using for this site? I’m getting fed up of WordPress because I’ve had problems with hackers and I’m looking at alternatives for another platform. I would be awesome if you could point me in the direction of a good platform.
Is there any possible way to implement this script into WordPress?
We’ve downloaded and installed a contact form using the Contact Form 7 plugin on our website.
One of the fields in the form submits a number (chosen by the user), to let us know how many items they have registered.
We are looking to integrate a counter with this form. Would like the counter to generate the total number of registered items.
Would it be possible to use your script in our WordPress site to get this working?
Thanks,
Lucille
The Collection Class is more about in-memory code. It doesn’t store anything. For what you’re talking about, you’d need to keep track of things with the database in the backend still. Hopefully that clears things up a little.
This is using wordpress. I’ve decided against re-inventing an already well-established wheel.