Using an Iterator Interface to Create “Round-Robin” Array

I had a requirement that seemed to need a way to cycle through a set of values in an array in such a way that when I got to the end of the array, it would start over at the beginning, essentially load-balancing the use of those array elements. Perhaps you might want to do the same thing for a set of ads, making sure a given user sees each available advertisement before starting again with the first (perhaps an array stored in $_SESSION?).

After exploring a few alternatives, one I found that I kind of like (for its elegance if not its lack of brevity) was to use PHP’s built-in Iterator interface. The concept here was to load any array into an instance of a class that implements the Iterator, and then simply using the Iterator::next() method to get the current value, then advance the array pointer, pointing it back to the beginning if it has reached the end of the array. Without further ado, the class:


<?php

class RoundRobin implements Iterator
{
    private 
$var = array();

    public function 
__construct($array)
    {
        if (
is_array($array)) {
            
$this->var $array;
        }
    }

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

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

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

    
/**
     * Get the current array element, then advance the pointer
     * @return mixed
     */
    
public function next()
    {
        
$var current($this->var);
        
next($this->var);
        if(!
$this->valid()) {
            
$this->rewind();
        }
        return 
$var;
    }

    public function 
valid()
    {
        
$key key($this->var);
        return (
$key !== NULL && $key !== FALSE);
    }
}

A sample usage:


<?php

$data 
= new RoundRobin(range(1,10));
$dbStuff getLotsOfStuffFromTheDB();
foreach(
$dbStuff as $stuff) {
    
$result getSomeMoreStuff($dbStuff['foo'], $data->next());
}

Danger, Will Robinson. Don’t do this, or you’ll have an endless loop:


<?php

$data 
= new RoundRobin(range(1,10));
foreach(
$data as $foo) {
    echo 
$foo "<br />\n";
}

Leave a Reply