Implementing the Iterator SPL Interface

In this second part of a series, I make the MySQLi_ResultWrapper class a full implementer of the Iterator SPL interface. Implementing the rest of the methods declared by the interface is a straightforward process that allows us to traverse MySQL result sets by using a plain “foreach” construct.

As you may know, the Standard PHP Library (commonly know as SPL) provides developers with a powerful set of native classes and interfaces that can be used for easily tackling problems that come up in everyday programming, such as autoloading resources on request, traversing recursively directories, overloading arrays, and so forth.

Due to the huge extension of the SPL, I don’t intend to cover in depth each of these classes and interfaces. You can read the PHP manual to get a more intimate background on them, or even pick up a good book that discusses the library from the basics to its most complex facets.

There are, however, some components included with the SPL that can be extremely useful in multiple scenarios and environments, which can be analyzed in detail without a degree in rocket science. That’s exactly the case with the Iterator, Countable and ArrayAccess interfaces. When used together, they allow programmers to build implementer classes that permit one to iterate over different data collections, such as file rows and database result sets, and manipulate them as if they were plain arrays.

To demonstrate how useful these interfaces can be, in the introductory part of this series I started developing a couple of MySQL abstraction classes. The first one was tasked with connecting to the server and running queries, and the second one was charged with handling data sets in different ways. I made the latter an implementer of the Iterator interface, which will allow us to traverse database rows by using simply a “foreach” construct.

Well, to be frank, this last class implemented only a part of the methods declared by Iterator. This issue must be properly addressed. Thus, in this second episode of the series I’m going to finish implementing the remaining methods defined by the Iterator interface, a process that hopefully will give you a clear idea of how to use it in a real-world context.

Ready to learn more about the handy Iterator, Countable and ArrayAccess SPL interfaces? Then click on the link below and read the next few lines!

{mospagebreak title=Review: partially implementing partially the Iterator SPL interface}

In case you haven’t had the chance to read the initial installment of this series, where I showed how to build a MySQL abstraction layer that implements the Iterator Interface, below I reintroduced the definitions of the classes composing this layer.

Here’s the wrapper class that, among other things, is tasked with connecting to MySQL and performing specified SQL queries:

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();

    }

}

Without digging too much into its internals, the above class is nothing but a simple wrapper for the native “MySQLi” class that comes with PHP 5. In this particular case, its “runQuery()” method returns an instance of another class called “MySQLi_ResultWrapper,” whose source code is listed below:

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();

    }

}

As you can see, here’s where the Iterator SPL interface comes into play. The previous “MySQLi_ResultWrapper” class is an implementer of it, even though, for the time being, this process is achieved only partially. But why am I saying this? Well, in case you don’t know, the interface declares five methods called “rewind(),” “current(),” “key(),” “valid()” and “next()” respectively.

However, at this moment the class only implements two of these, that is “rewind()” and “valid(),” which isn’t very useful. If you give the class a try, you’ll get a fatal error from the PHP engine. For obvious reasons, it’s necessary to implement the remaining interface methods, thus giving the class the ability to traverse data sets using an array-like notation.

In the section to come I’m going to complete the implementation process. Now, click on the link below and keep reading.

{mospagebreak title=Implementing the remaining methods of the Iterator interface}

As I said in the previous segment, it’s mandatory to implement within the “MySQLi_ResultWrapper” class the rest of the methods declared by the Iterator interface. In reality, this process is pretty straightforward, and the code fragment below will hopefully demonstrate my point:

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

public function key()

{

    return $this->_pointer;

}

 

 

// move forward result set pointer (implementation required by ‘next()’ method in Iterator interface)

public function next()

{

    ++$this->_pointer;

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

    return $this;

}

 

 

// determine if result set pointer is valid or not (implementation required by ‘valid()’ method in Iterator interface)

public function valid()

{

    return $this->_pointer < $this->num_rows;

}

 

Didn’t I tell you that the implementation of the remaining methods declared by the Iterator interface was going to be easy to understand? Well, the code sample above should reaffirm this concept, since now those methods give the “MySQLi_ResultWrapper” class an API that permits us to traverse database result sets as if they were regular arrays, aside from allowing the internal pointer to move back and forth.

So far, so good. Now that the methods have a shiny new implementation, it’s time to show the full source code of the “MySQLi_ResultWrapper” class, so you can see how it looks after adding the methods to it.

This will be done in the following segment, so click on the link shown below and read the following lines. 

{mospagebreak title=The full source code of the MySQLi_ResultWrapper class}

If you’re anything like me, then you want to see the finished version of the previous “MySQLi_ResultWrapper” class, now that it fully implements the Iterator SPL interface. In that case, look at the following example, which shows the class’s source code:

  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();

    }

   

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

    public function key()

    {

        return $this->_pointer;

    }

   

    // move forward result set pointer (implementation required by ‘next()’ method in Iterator interface)

    public function next()

    {

        ++$this->_pointer;

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

        return $this;

    }

   

    // determine if result set pointer is valid or not (implementation required by ‘valid()’ method in Iterator interface)

    public function valid()

    {

        return $this->_pointer < $this->num_rows;

    }

}

Mission accomplished. Now the “MySQLi_ResultWrapper” class suits the requirements imposed by Iterator, as it implements all of the interface’s methods. Even though at this point the class is capable of iterating over a retrieved data set by using a “foreach” loop, it does not have a method that allows it to count the number of rows in the set.

Fortunately, this issue can be easily addressed by making the class an implementer of the Countable SPL interface. However, that will be addressed in the next tutorial in this series. 

Final thoughts

In this second part of the series, I made the previous "MySQLi_ResultWrapper” class a full implementer of the Iterator SPL interface. As you saw for yourself, implementing the rest of the methods declared by the interface was indeed a straightforward process, and allowed us to traverse MySQL result sets by using a plain “foreach” construct.

In the upcoming tutorial, I’m going to give the aforementioned class the ability to count rows in data sets by implementing the “count()” method declared by the Countable SPL interface.

Don’t miss the forthcoming article!

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

chat sex hikayeleri Ensest hikaye