The Iterator, Countable and ArrayAccess SPL Interfaces

In this first part of a short series, I’m going to introduce you to using the Iterator, Countable and ArrayAccess interfaces that come with the Standard PHP Library. You’ll see how to implement some of the methods declared by the Iterator interface within a class that manipulates MySQL result sets via an intuitive API.

For many PHP developers eager to apply the object-oriented paradigm in a more thorough and consistent manner, the release of PHP 5 brought a number of handy features that allowed them to achieve this goal in a truly painless fashion. This isn’t breaking news, of course, but the inclusion of member visibility and abstract classes, the support for native exceptions and magic methods, to name just a few examples, gave the language the level of maturity that we see in it these days.

In addition, among the features that were added to PHP 5, there exists the capacity for creating user-defined interfaces. This characteristic permits developers to do programming by contract without too many headaches. However, the support for interfaces doesn’t stop in “userland,” as the language also comes with the Standard PHP Library (SPL). The SPL includes a set of native classes and interfaces that make it easier to tackle common programming problems, such as overloading arrays, traversing directories recursively, and so forth.

Included in the group of native interfaces bundled with the SPL, there are a few  that deserve a deeper analysis, as they’re frequently used by many developers nowadays. I’m talking specifically about the Iterator, Countable and ArrayAccess interfaces. When properly implemented, these interfaces allow you to traverse different data collections (e.g. database result sets) by using a simple “foreach” construct, as well as going backward and forward across those data, as when navigating regular arrays.

Given the relevance that these native interfaces have for the average PHP developer, in this series of tutorials I’m going to demonstrate how to use them in the development of a pair of concrete classes, which as you’ll see in a few moments, will act like an abstraction layer for interacting with MySQL.

Now, it’s time to start discovering the actual power behind the Iterator, Countable and ArrayAccess PHP 5 interfaces. Let’s jump in!

{mospagebreak title=Developing a basic MySQL abstraction class}

As I mentioned in the introduction, one of the most typical use of the native Iterator, Countable and ArrayAccess interfaces occurs when developing classes that have the ability tor traverse database result sets. In this particular situation, since my goal is to demonstrate how to implement the interfaces in a useful way, in the lines to come I’m going to start building a pair of classes that will work specifically with MySQL.

However, it’s possible to use the same interfaces with other popular RDBMS, such as MS SQL and Oracle. In theory you shouldn’t have major problems building classes that will work with those database servers, and will probably make use of the standard PDO extension (PHP Data Objects).

Thus, to begin, the first of two classes that I plan to build will be a proxy for the native MySQLi PHP 5 class, and its initial definition will be as follows:

class MySQLiWrapper extends MySQLi

{

   

   private static $_instance = NULL;

 

 

   // return Singleton instance of MySQL class

   public static function getInstance(array $config = array())

   {

       if (self::$_instance === NULL)

       {

          self::$_instance = new self($config);

       }

       return self::$_instance;

   }

  

   // private constructor

   private function __construct(array $config)

   {

        if (count($config) < 4)

        {

            throw new Exception(‘Invalid number of connection parameters’);  

        }

       list($host, $user, $password, $database) = $config;

       parent::__construct($host, $user, $password, $database);

        if ($this->connect_error)

        {

            throw new Exception(‘Error connecting to MySQL : ‘ . $this->connect_errno . ‘ ‘ . $this->connect_error);

        }

   }

 

 

    // prevent cloning class instance

    private function __clone(){}

   

    // perform query

    public function runQuery($query)

    {

        if (is_string($query) AND !empty($query))

        {

            if ((!$this->real_query($query)))

            {

                throw new Exception(‘Error performing query ‘ . $query . ‘ – Error message : ‘ . $this->error);

            }

            return new MySQLi_ResultWrapper($this);

        }

    }

   

    // get insertion ID

    public function getInsertID()

    {

        return $this->insert_id;

    }

   

    // close database connection

    public function __destruct()

    {

        $this->close();

    }

}

 

As I anticipated a moment ago, the previous “MySQLiWrapper” class is a Singleton wrapper for the native MySQLi class that comes with PHP 5. Essentially, all that this wrapper does is implement some straightforward methods, which allow you to connect to MySQL, run hard-coded SQL queries, retrieve insertion IDs, and so forth.

While it’s fair to say that this first sample class does perform a few interesting tasks like the ones mentioned above, there’s still no clue as to how it can implement some of the interfaces discussed in the introduction. Or is there? Well, if you analyze the implementation of the “runQuery()” method more closely, you’ll realize that it returns a new object, which is an instance of an undefined class called “MySQLi_ResultWrapper.”

The reason to code this method in such a way is simply the separation of concerns. On the one hand, there’s one class that take cares of establishing a connection to MySQL and executing queries, while on the other hand there will be a separate class that will handle database result sets generated by “SELECT” statements. That’s quite easy to understand, right?

Since the purpose of the still-undefined “MySQLi_ResultWrapper” class will be manipulating row sets, it becomes a good candidate for turning into an implementer of the pertinent Iterator, Countable and ArrayAccess interfaces. This will  allow us to traverse and count table records, as well as navigate easily across them.

Therefore, provided that you grasped the logic driving the previous “MySQLiWrapper” class, it’s time to show the definition of “MySQLi_ResultWrapper,” which at its initial stage will implement the methods defined by the Iterator interface.

To learn how this brand new class will be created, read the section to come. I’ll be there, waiting for you.

{mospagebreak title=Handling database result sets separately}

In the previous segment, I defined an initial abstraction class that permitted us, among other things, to handle connections to MySQL and perform specified SQL queries through a friendly API. Naturally, the most important method to look at here is “runQuery().” It returns an instance of a class called “MySQLi_ResultWrapper,” whose definition certainly hasn’t been showed so far.

Thus, it’s time to reveal the secret and show the initial source code of this class, which will be an implementer of the aforementioned Iterator, Countable and ArrayAccess native interfaces respectively. But I’m getting ahead of myself; for the moment, this class will look like this: 

class MySQLi_ResultWrapper extends MySQLi_Result

{

    private $_pointer = 0;

   

   // fetch row as an object

    public function fetchObject()

    {

        if (!$row = $this->fetch_object())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch row as an associative array

    public function fetchAssocArray()

    {

        if (!$row = $this->fetch_assoc())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch row as an enumerated array

    public function fetchNumArray()

    {

        if (!$row = $this->fetch_row())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch all rows

    public function fetchAll($type = MYSQLI_ASSOC)

    {

        if ($type !== MYSQLI_ASSOC AND $type !== MYSQLI_NUM AND $type !== MYSQLI_BOTH)

        {

            $type = MYSQLI_ASSOC;

        }

        if (!$rows = $this->fetch_all($type))

        {

            return NULL;

        }

        return $rows;  

    }

   

    // get definition information on fields

      public function fetchFieldsInfo()

    {

        if (!$fieldsInfo = $this->fetch_fields())

        {

            throw new Exception(‘No information available for table fields.’);

        }

        return $fieldsInfo;

    }

   

    // get definition information on next field

    public function fetchFieldInfo()

    {

        if (!$fieldInfo = $this->fetch_field())

        {

            throw new Exception(‘No information available for current table field.’);   

        }

        return $fieldInfo;

    }

   

    // free up result set

    public function __destruct()

      {

        $this->close();

    }

}          

From the above code sample, it’s clear to see that the “MySQLi_ResultWrapper” class is exactly that: a wrapper for the native PHP 5 MySQLi_Result class. In consonance with this, the class implements some proxy methods that allow it to fetch database rows as plain objects, as well as in the form of numerically-indexed and associative arrays. Besides, there are a couple of additional methods that can be used for retrieving information about the fields of a selected table, these don’t bear any further discussion.

At this point, the definition of the “MySQLi_ResultWrapper” class is quite easy to follow, but it doesn’t implement any of the interfaces mentioned before. Well, as the old proverb says, a long walk begins with a single step, so it’s time to refactor the class a little bit to make an implementer of the Iterator interface. This process will permit us to iterate over database result sets via a simple “foreach” construct.

This topic will be discussed in detail in the section to come. Therefore, to get there, click on the link below and keep reading. 

{mospagebreak title=Making the MySQLi_ResultWrapper class more functional}

In case you don’t know, the native Iterator interface declares five methods called “rewind(),” “current(),” “key(),” “valid()” and “next().” This implies, obviously, that any class implementing the interface must give a concrete implementation to each of these methods. In the case of the previous “MySQLi_ResultWrapper” class,  turning it into an implementer of Iterator will make it possible to traverse database result sets using a “foreach” loop, as if they were plain arrays.

Now, it’s time to refactor the class in question, so it can partially implement the methods declared by Iterator. After the corresponding refactoring process, the “MySQLi_ResultWrapper” class will have the following definition: 

  class MySQLi_ResultWrapper extends MySQLi_Result implements Iterator

{

    private $_pointer = 0;

   

   // fetch row as an object

    public function fetchObject()

    {

        if (!$row = $this->fetch_object())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch row as an associative array

    public function fetchAssocArray()

    {

        if (!$row = $this->fetch_assoc())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch row as an enumerated array

    public function fetchNumArray()

    {

        if (!$row = $this->fetch_row())

        {

            return NULL;

        }

        return $row;

    }

   

    // fetch all rows

    public function fetchAll($type = MYSQLI_ASSOC)

    {

        if ($type !== MYSQLI_ASSOC AND $type !== MYSQLI_NUM AND $type !== MYSQLI_BOTH)

        {

            $type = MYSQLI_ASSOC;

        }

        if (!$rows = $this->fetch_all($type))

        {

            return NULL;

        }

        return $rows;   

    }

   

    // get definition information on fields

      public function fetchFieldsInfo()

    {

        if (!$fieldsInfo = $this->fetch_fields())

        {

            throw new Exception(‘No information available for table fields.’);

        }

        return $fieldsInfo;

    }

   

    // get definition information on next field

    public function fetchFieldInfo()

    {

        if (!$fieldInfo = $this->fetch_field())

        {

            throw new Exception(‘No information available for current table field.’);   

        }

        return $fieldInfo;

    }

   

    // move pointer in result set to specified offset

    public function movePointer($offset)

    {

        $offset = abs((int)$offset);

        $limit = $this->num_rows – 1;

        if ($limit <= 0 OR $offset > $limit)

        {

            return NULL;

        }

        unset($limit);

        return $this->data_seek($offset);

      }

       

    // reset result set pointer (implementation required by ‘rewind()’ method in Iterator interface)

    public function rewind()

    {

        $this->_pointer = 0;

        $this->movePointer($this->_pointer);

        return $this; 

    }

   

    // get current row set in result set (implementation required by ‘current()’ method in Iterator interface)

    public function current()

    {

        if (!$this->valid())

        {

            throw new Exception(‘Unable to retrieve current row.’);

        }

        $this->movePointer($this->_pointer);

        return $this->fetchObject();

    }

   

    // free up result set

    public function __destruct()

      {

        $this->close();

    }

}

Definitely, the above “MySQLi_ResultWrapper” class is starting to take shape. It’s now an implementer of the Iterator interface, and in consequence it must implement all of its declared methods. For the moment, the class only does this with the “rewind()” and “current()” inherited methods, which internally use another one called “movePointer()” in order to reset the pointer of a given result set and get its current element.

Naturally, if you give the class a try in its current state, you’ll get a loud complaint from the PHP engine, since it doesn’t implement all of the methods of Iterator. However, this is a work in progress; the remaining methods will be properly defined in the upcoming tutorial.

Final thoughts

In this first chapter of the series, I introduced you to using the Iterator, Countable and ArrayAccess interfaces that come packaged with the Standard PHP Library. This part showed how to implement only some of the methods declared by the Iterator interface within a class that manipulates MySQL result sets via an intuitive API.

In the next installment, things will get more interesting. I’m going to finish building this class by giving a concrete implementation to the Iterator’s remaining methods.

Here’s my final piece of advice: don’t miss the next part!

[gp-comments width="770" linklove="off" ]

chat