Home arrow PHP arrow Page 2 - Using the ArrayAccess SPL Interface

Review: implementing the Iterator and Countable SPL interfaces - PHP

In this fourth part of a six-part series, that covers the Iterator, Countable, and ArrayAccess SPL interfaces, I show how to partially implement the methods declared by the ArrayAccess SPL interface within a sample class that manipulates MySQL result sets.

TABLE OF CONTENTS:
  1. Using the ArrayAccess SPL Interface
  2. Review: implementing the Iterator and Countable SPL interfaces
  3. Implementing the ArrayAccess SPL interface's offsetExists() method
  4. Adding an offsetSet() method
By: Alejandro Gervasio
Rating: starstarstarstarstar / 1
April 06, 2010

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

In case you haven't read the previous part of this series, where I explained how to make the MySQLi wrapper class mentioned in the introduction an implementer of the Countable SPL interface, I included the complete definitions of the classes that comprise this example, starting with the one that connects to MySQL, run hard-coded queries and so forth.

Here's how this class was originally 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();

    }

}

At first glance, the logic that drives the above "MySQLiWrapper" class seems to be hard to follow, but the truth is that its inner workings are pretty easy to grasp, trust me. Essentially, all that this class does is perform some MySQL-related tasks, such as establishing a connection to the server, executing queries, and so on. Naturally, if you're like me, then you'll have focused your attention on the "runQuery()" method. This method, after running a given SQL statement, returns to client code an instance of a class named "MySQLi_ResultWrapper."

This one is an implementer of the Iterator and Countable SPL interfaces, and its definition is shown below. Take a look, please:

class MySQLi_ResultWrapper extends MySQLi_Result implements Iterator, 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;

    }

} 

Undoubtedly, implementing the Iterator and Countable interfaces isn't rocket science, and the previous code fragment demonstrates this pretty clearly. In this case, the "MySQLi_ResultWrapper" class gives a concrete definition to the methods declared by these interfaces, which allows you to treat rows contained in database result sets as simple array elements.

While this is all well and good, it's fairly easy to make this class even more functional by turning it into an implementer of the ArrayAccess interface. In doing so, it'd be feasible to retrieve specific records in a data set by way of its offset. However, to achieve this the class must include all four of the methods declared by ArrayAccess, which are "offsetExists()," "offsetGet()," "offsetSet()" and "offsetUnset()" respectively.

Therefore, in the following segment I'm going to show you how to accomplish this in a painless way. Now, go ahead and read the section to come. It's only one click away.



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: