Home arrow PHP arrow Page 4 - Iterators in the Simplest Sense: Traversing Different Data Structures

More iterators ahead: creating a MySQL result set iterator class - PHP

Here we are again. Welcome to the second tutorial of the series “Iterators in the simplest sense.” Just in case you didn’t know, this series introduces Iterators in PHP 4 – PHP 5, explaining their basic concepts, and teaches you how to use them in practical projects, which can be utilized as part of larger PHP applications.

TABLE OF CONTENTS:
  1. Iterators in the Simplest Sense: Traversing Different Data Structures
  2. Extending the scope of iterators: building a file iterator class
  3. Building a concrete example: using the “FileIterator” class
  4. More iterators ahead: creating a MySQL result set iterator class
By: Alejandro Gervasio
Rating: starstarstarstarstar / 9
March 15, 2006

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Having available an array iterator class, which is seated on top of the sample classes hierarchy, defining a MySQL result set iterator class is actually a straightforward task. All I have to do is derive another subclass from the respective parent array iterator class, and the job is almost done. Since I want to create a full object-oriented example, I’ll include a couple of additional classes, where the first one is a MySQL abstraction class and the second one is a MySQL result set processing class.

If you’ve already read some of my previous PHP articles, you’ll find these classes very familiar, so they shouldn’t be particularly hard to understand. That said, here is the signature for the corresponding MySQL wrapping class:

class MySQL {
    var $conId; // connection identifier
    var $host; // MySQL host
    var $user; // MySQL username
    var $password; // MySQL password
    var $database; // MySQL database
    // constructor
    function MySQL($options=array()){
    // validate incoming parameters
        if(count($options)>0){
            foreach($options as $parameter=>$value){
                if(empty($value)){
                    trigger_error('Invalid parameter
'.$parameter,E_USER_ERROR);
                }
                $this->{$parameter}=$value;
            }
            // connect to MySQL
            $this->connectDB();
        }
        else {
            trigger_error('No connection parameters were
provided',E_USER_ERROR);
        }
    }
    // connect to MYSQL server and select database
    function connectDB(){
        if(!$this->conId=mysql_connect($this->host,$this-
>user,$this->password)){
            trigger_error('Error connecting to the
server',E_USER_ERROR);
        }
        if(!mysql_select_db($this->database,$this->conId)){
             trigger_error('Error selecting
database',E_USER_ERROR);
        }
    }
    // perform query
    function query($query){
        if(!$this->result=mysql_query($query,$this->conId)){
            trigger_error('Error performing query
'.$query,E_USER_ERROR);
        }
        // return new Result object
        return new Result($this,$this->result); 
    }
}

Having listed the source code for this simple MySQL abstraction class, I’ll go ahead with showing the code for the respective MySQL “Result” class. Here you have it:

class Result {
    var $mysql; // instance of MySQL object
    var $result; // result set
    function Result(&$mysql,$result){
        $this->mysql=&$mysql;
        $this->result=$result;
    }
    // fetch row
    function fetchRow(){
        return mysql_fetch_array($this->result,MYSQL_ASSOC);
    }
    // count rows
    function countRows(){
        if(!$rows=mysql_num_rows($this->result)){
            trigger_error('Error counting rows',E_USER_ERROR);
        }
        return $rows;
    }
    // count affected rows
    function countAffectedRows(){
        if(!$rows=mysql_affected_rows($this->mysql->conId)){
            trigger_error('Error counting affected
rows',E_USER_ERROR);
        }
        return $rows;
    }
    // get ID from last inserted row
    function getInsertID(){
        if(!$id=mysql_insert_id($this->mysql->conId)){
            trigger_error('Error getting ID',E_USER_ERROR);
        }
        return $id;
    }
    // seek row
    function seekRow($row=0){
        if(!mysql_data_seek($this->result,$row)){
            trigger_error('Error seeking data',E_USER_ERROR);
        }
    }
    function getQueryResource(){
        return $this->result;
    }
}

Finally, now that you know how the above complementary classes were appropriately defined, here’s the signature for the “ResultIterator” class:

class ResultIterator extends ArrayIterator{
    function ResultIterator($result){
        if(get_resource_type($result)!='mysql result'){
            trigger_error('Input data must be a MySQL result
set',E_USER_ERROR);
        }
        while($row=mysql_fetch_row($result)){
            $this->data[]=implode('',$row);
        }
    }
}

As shown above, the “ResultIterator” class is created by deriving a subclass from the base array iterator. Since its definition is extremely simple, the only thing worth noting here is the checking process that is performed by the constructor, in order to make sure that only MySQL result sets are passed in as incoming arguments. Finally, the entire result set is stored in the “$this->data” array, which is very convenient for traversing with minor hassles.

Of course, as with everything in life, this versatility comes at a cost: if a SQL query returns a large number of database records, it might cause some performance issues, since the data will be stored in server memory. To solve this problem, you can either write an iterator class that only acts on native MySQL datasets without using additional arrays, or use the approach I showed you before, in case your database tables only hold a relatively small number of records.

Having clarified this performance point, below is an example of how to use the “ResultIterator” class:

// include class files
require_once 'mysqlclass.php';
require_once 'resultclass.php';
// connect to MySQL
$db=&new MySQL(array('host'=>'host','user'=>'user','password'=>'password',
'database'=>'database'));
// get result set
$result=$db->query('SELECT * FROM mytable');
// use 'ResultIterator' class
$rIterator=&new ResultIterator($result->getQueryResource());
// display first row of the result set
echo $rIterator->reset();
// display current row of the result set
echo $rIterator->current();
// display next row of the result set
echo $rIterator->next();
// display final row of the result set
echo $rIterator->end();
// display previous row of the result set
echo $rIterator->prev();
// seek row within result set
echo $rIterator->seek(4);
// count number of rows in result set
echo $rIterator->count();

As shown in the example above, traversing a MySQL result set back and forth is a simple process. It’s just a matter of calling the corresponding methods of the “ResultIterator” class, in order to move the internal data pointer (in fact it’s an array pointer), across the whole dataset. Notice the functionality encapsulated within these methods, which can be used together, in order to perform more complex operations inside a specific PHP application.

At this stage, hopefully you learned the basics of Iterators in PHP, accompanied by numerous hands-on examples of how to build several PHP classes, in order to traverse different data structures. Of course, the examples I showed here should be considered introductory samples that can be used for starting quickly with using Iterators in PHP.

To wrap up

Now this article has concluded. During this second part of this series, I demonstrated the process for building different PHP 4 iterators in a friendly way. I hope the code samples you saw here can be helpful for expanding your overall knowledge on Design Patterns, as well as on object-oriented programming in PHP.

Throughout the last installment of the series, I’ll cover Iterators in PHP 5, which is really an interesting topic, due to the great capabilities offered by the SPL (Standard PHP Library). See you in the last tutorial!



 
 
>>> 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: