Coding Examples of the Iterator, Countable and ArrayAccess SPL Interfaces in PHP 5

Welcome to the final installment of a series that provides an overview of the Iterator, Countable and ArrayAccess SPL interfaces in PHP 5. Made up of six parts, this series teaches you how to build a fully-working MySQL abstraction class that takes advantage of the methods inherited from these native interfaces to manipulate database record sets easily by using an array syntax.

In the articles that preceded this one I demonstrated in a step-by-step fashion how to develop such a MySQL handling class. It effectively defined all of the methods required by the aforementioned interfaces. In doing so, the class now is not only capable of traversing data sets by way of a plain “foreach” construct, but it allows you to count and access rows in those sets as if they were array elements.

Of course, while describing the functionality of this sample class is fine, bragging about it is only the half of the story. It’s necessary to show a few examples of how to use the class in a useful way. Therefore, in this last part of the series I’m going to code for you a few basic scripts that will show the actual functionality of this implementing class.

Does my proposal sound good to you? Then start reading now!

{mospagebreak title=Review: the MySQLiWrapper and MySQLi_ResultWrapper classes}

Before I start coding some sample scripts that show how to work with the implementing “MySQLi_ResultWrapper” class, I’d like to reintroduce its definition, just in case you haven’t had the chance to study it in depth. So, here’s how this class was developed:

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

    }

}

Since this class has been discussed in previous part of the series, I’m not going to waste your time (and mine) explaining how it works. Instead, I suggest you pay attention to the class below, which is an implementer of the Iterator, Countable and ArrayAccess SPL interfaces mentioned in the introduction:

class MySQLi_ResultWrapper extends MySQLi_Result implements Iterator, ArrayAccess, Countable

{

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

    }

    

    // count rows in result set (implementation required by ‘count()’ method in Countable interface)

    public function count()

    {

        return $this->num_rows;

    }

   

    // 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;

    }

   

    // determine if the given offset exists (implementation required by ‘offsetExists()’ method in ArrayAccess interface)

    public function offsetExists($offset)

    {

        $this->movePointer($offset);

        $row = $this->fetchObject();

        return isset($row);

    }

   

    // get row according to given offset (implementation required by ‘offsetExists()’ method in ArrayAccess interface)

    public function offsetGet($offset)

    {

        $this->_pointer = abs((int)$offset);

        return $this->current();

    }

   

    // not implemented (required by ‘offsetSet()’ method in ArrayAccess interface)

    public function offsetSet($offset, $value){}

   

        // not implemented (required by ‘offsetUnset()’ method in ArrayAccess interface)

    public function offsetUnset($offset){}

   

    // free up result set

    public function __destruct()

    {

        $this->close();

    }

}

While the definition of the above “MySQLi_ResultWrapper” class is somewhat long, it is easy to follow, since most of its methods are inherited from the Iterator, Countable and ArrayAccess native interfaces. At this point, you’ll surely be wondering what this buys us. Well, as I explained in the introduction, thanks to this inheritance, the class can be used to manipulate MySQL data sets as if they were plain PHP arrays.

To demonstrate this, though, it’s necessary to code some scripts that show the veracity of this claim. Therefore, in the following segment I’m going to write an example that will show how to utilize an instance of the “MySQLi_ResultWrapper” class to traverse a simple database result set.

To learn how this example will be coded, click on the link below and keep reading.

{mospagebreak title=Putting the MySQLi_ResultWrapper class to work}

If you’re like me, then you want to learn how to work with the previous “MySQLi_ResultWrapper” class, right? Below I coded a script that shows the benefits of making this class an implementer of the Iterator interface.

The script in question is as follows:

<?php

 

 

try

{

    // connect to MySQL

    $db = MySQLiWrapper::getInstance(array(‘host’, ‘user’, ‘password’, ‘database’));

   

    // perform query

    $result = $db->runQuery(‘SELECT * FROM users’);

   

    // traverse rows in result set

    foreach ($result as $user)

    {

        echo ‘<p>First Name: ‘ . $user->fname . ‘, Last Name : ‘ . $user->lname . ‘</p>';  

    }

   

    // reset result pointer

    $result->rewind();

   

    // display result pointer

    echo ‘Result pointer : ‘ . $result->key();

   

    // display data in current row

    $user = $result->current();

    echo ‘<p>First Name: ‘ . $user->fname . ‘, Last Name : ‘ . $user->lname . ‘</p>';

   

    // move forward result pointer

    $result->next();

   

    // display result pointer

    echo ‘Result pointer : ‘ . $result->key();

   

    // display data in current row

    $user = $result->current();

    echo ‘<p>First Name: ‘ . $user->fname . ‘, Last Name : ‘ . $user->lname . ‘</p>';

   

    // reset result pointer

    $result->rewind();

}

 

 

// catch exceptions

catch(Exception $e)

{

    echo $e->getMessage();

    exit();

As the above code sample shows, it’s extremely easy to traverse a database result set by using a “foreach” loop. Once the data have been fetched from a sample “users” table, thanks to the implementation of the Iterator interface, traversing the records is a breeze. In addition, the example demonstrates how to explicitly use the “rewind(),” “current()” and “key()” methods, which allow you to freely navigate the result set.

So far, so good. Now that you’ve grasped the logic driving the previous code sample, it’s time to show how to use the “count(),” “offsetExists()” and “offsetGet()” methods. This example will be the appropriate conclusion to this tutorial, so click on the link that appears below and read the following segment.

{mospagebreak title=Final script: counting rows in a result set and accessing specified records}

As I said in the section that you just read, I’m going to finish this tutorial by coding an example that demonstrates how to use the “count(),” “offsetExists()” and “offsetGet()” methods implemented by the “MySQLi_ResultWrapper” class. These will allow you to count rows in a given result set, as well as access specified elements in it.

The code sample that performs all of these tasks is as follows:

<?php

 

 

try

{

    // connect to MySQL

    $db = MySQLiWrapper::getInstance(array(‘host’, ‘user’, ‘password’, ‘database’));

   

    // perform query

    $result = $db->runQuery(‘SELECT * FROM users’);

       

    // count the number of rows in result set

    echo ‘Number of rows: ‘ . $result->count();

   

    // check if given offset exists

    if ($result->offsetExists(1))

    {

        echo ‘Row exists!';

    }

    else

    {

        echo ‘Row does not exists!';

    }

   

    // get a row according to a given offset

    $user = $result->offsetGet(1);

    echo ‘<p>First Name: ‘ . $user->fname . ‘, Last Name : ‘ . $user->lname . ‘</p>';

}

 

 

// catch exceptions

catch(Exception $e)

{

    echo $e->getMessage();

    exit();

}  

Once again, the earlier code fragment shows in a nutshell why implementing the Countable and ArrayAccess SPL interfaces is so convenient. In this particular case, the methods inherited from the interfaces are used to determine the number of rows contained in a data set, and to access a specific record by its offset.

And with this last example, I’m finishing this article that explores the Iterator, Countable and ArrayAccess interfaces packaged with the Standard PHP Library. Feel free to edit all of the code fragments shown in this article. Doing this will surely give you more ideas for how to implement these interfaces in a few other creative ways.

Final thoughts

Sad but true, we’ve come to the end of this series. Hopefully, the code samples shown in its six parts will give you a good idea of how to implement the Iterator, Countable and ArrayAccess SPL interfaces within different classes.

As you saw for yourself, in this particular case the interfaces were implemented by a class that processes MySQL result sets, but naturally they can be used for constructing classes that will handle different data collections, such as XML nodes and flat text files rows. The possibilities and endless.

See you in the next PHP tutorial!

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

antalya escort bayan antalya escort bayan Antalya escort diyarbakir escort