PHP
  Home arrow PHP arrow Page 4 - Iterators in the Simplest Sense: Traversing Data Structures in PHP 5
Dev Shed Forums  
Administration  
AJAX  
Apache  
BrainDump  
DHTML  
Flash  
Java  
JavaScript  
Multimedia  
MySQL  
Oracle  
Perl  
PHP  
Practices  
Python  
Reviews  
Security  
Smartphone Development  
Style-Sheets  
Web Services  
XML  
Zend  
Zope  
Mobile Linux  
App Generation ROI  
IBM® developerWorks  
Forums Sitemap  
E-Commerce Hosting  
Linux Web Hosting  
Managed Hosting  
Small Business Hosting  
VPS Hosting  
Weekly Newsletter

 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid  
Request Media Kit
Contact Us  
Site Map  
Privacy Policy  
Support  
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
Google.com  
PHP

Iterators in the Simplest Sense: Traversing Data Structures in PHP 5
By: Alejandro Gervasio
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: starstarstarstarstar / 7
    2006-03-22


    Table of Contents:
  • Iterators in the Simplest Sense: Traversing Data Structures in PHP 5
  • Working with iterators in PHP 5: using some predefined SPL classes
  • Traversing text files the easy way: the brand new FileIterator class
  • Traversing database result sets: building a MySQL iterator class

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      error-file:tidyout.log Del.ici.ous error-file:tidyout.log Digg
      error-file:tidyout.log Blink error-file:tidyout.log Simpy
      error-file:tidyout.log Google error-file:tidyout.log Spurl
      error-file:tidyout.log Y! MyWeb error-file:tidyout.log Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article

     
     
    ADVERTISEMENT


    Iterators in the Simplest Sense: Traversing Data Structures in PHP 5 - Traversing database result sets: building a MySQL iterator class
    ( Page 4 of 4 )

    As I said before, my last example on building iterator classes in PHP 5 comprised a simple yet efficient MySQL iterator class. If you're planning to create a dataset paging system without appealing to hard-to-code routines, this iterator might fit your needs. But, first of all, let me show you how this class actually looks. Its definition is as follows:

    class ResultIterator{
        private $iterator;
        public function __construct($result){
            if(get_resource_type($result)!='mysql result'){
                throw new Exception('result must be a MySQL result
    set');
            }
            // get ArrayObject
            $arrayobj=new ArrayObject();
            // get Iterator object
            $this->iterator=$arrayobj->getIterator();
            while($row=mysql_fetch_row($result)){
                $arrayobj[]=implode('',$row);
            }
        }
        // reset pointer of MySQL result set
        public function rewind(){
            return $this->iterator->rewind();
        }
        // get current row
        public function current(){
            if($this->iterator->valid()){
                return $this->iterator->current();
            }
        }
        // get next row
        public function next(){
            if($this->iterator->valid()){
                return $this->iterator->next();
            }
        }
        // seek row
        public function seek($pos){
            if(!is_int($pos)||$pos<0){
                throw new Exception('Invalid position');
            }
            return $this->iterator->seek($pos);
        }
        // count rows
        public function count(){
            return $this->iterator->count();
        }
    }

    As you can see, the definition for the above "ResultIterator" class reaffirms the concepts that I explained at the beginning of this article. In this case I built this iterator class by redefining the same set of methods exposed by the previous "FileIterator." Doing so, it's possible to access a given MySQL data set by using the identical bunch of methods (also called an interface).

    Regarding the definition of the class constructor, it's clear to see that it reuses the "ArrayObject" class, in order to store each dataset row as a new element of the pertinent array structure. Also, the following checking block:

    if(get_resource_type($result)!='mysql result'){
        throw new Exception('result must be a MySQL result set');
    }  

    makes sure that only valid MySQL result sets are passed as input parameters to the constructor. Of course, as I explained before, the remaining "rewind()," "current()," "next()" methods, etc., are properly redefined within the class; thus they can be used to iterate over the corresponding database result set.

    After defining the previous "ResultIterator" class, here's a possible implementation, in this case integrated with a couple of MySQL processing classes:

    // define 'MySQL' class
    class MySQL{
        private $host;
        private $user;
        private $password;
        private $database;
        private $connId;
        // constructor
        function __construct($options=array()){
            if(!is_array($options)){
                throw new Exception('Connection options must be an
    array');
            }
            foreach($options as $option=>$value){
                if(empty($option)){
                    throw new Exception('Connection parameter cannot
    be empty');
                }
                $this->{$option}=$value;
            }
            $this->connectDb();
        }
        // private 'connectDb()' method
        private function connectDb(){
            if(!$this->connId=mysql_connect($this->host,$this-
    >user,$this->password)) {
                throw new Exception('Error connecting to MySQL');
            }
            if(!mysql_select_db($this->database,$this->connId)){
                throw new Exception('Error selecting database');
            }
        }
        // public 'query()' method
        public function query($sql){
            if(!$result=mysql_query($sql)){
                throw new Exception('Error running query '.$sql.' '.mysql_error());
            }
            return new Result($this,$result);
        }
    }
    // define 'Result' class
    class Result{
        private $mysql;
        private $result;
        // constructor
        public function __construct($mysql,$result){
            $this->mysql=$mysql;
            $this->result=$result;
        }
        // public 'fetch()' method
        public function fetch(){
            return mysql_fetch_array($this->result,MYSQL_ASSOC);
        }
        // public 'count()' method
        public function count(){
            if(!$rows=mysql_num_rows($this->result)){
                throw new Exception('Error counting rows');
            }
            return $rows;
        }
        // public 'get_insertId()' method
        public function getInsertId(){
            if(!$insId=mysql_insert_id($this->mysql->connId)){
                throw new Exception('Error getting insert ID');
            }
            return $insId;
        }
        // public 'seek()' method
        public function seek($row){
            if(!int($row)&&$row<0){
                throw new Exception('Invalid row parameter');
            }
            if(!$row=mysql_data_seek($this->mysql->connId,$row)){
                throw new Exception('Error seeking row');
            }
            return $row;
        }
        // public 'getAffectedRows()' method
        public function getAffectedRows(){
            if(!$rows=mysql_affected_rows($this->mysql->connId)){
                throw new Exception('Error counting affected rows');
            }
            return $rows;
        }
        // public 'getQueryResource()' method
        public function getQueryResource(){
            return $this->result;
        }
    }
    // define 'ResultIterator' class
    class ResultIterator{
        private $iterator;
        public function __construct($result){
            if(get_resource_type($result)!='mysql result'){
                throw new Exception('result must be a MySQL result set');
                            }
            // get ArrayObject
            $arrayobj=new ArrayObject();
            // get Iterator object
            $this->iterator=$arrayobj->getIterator();
            while($row=mysql_fetch_row($result)){
                $arrayobj[]=implode('',$row);
            }
        }
        // reset pointer of MySQL result set
        public function rewind(){
            return $this->iterator->rewind();
        }
        // get current row
        public function current(){
            if($this->iterator->valid()){
                return $this->iterator->current();
            }
        }
        // get next row
        public function next(){
            if($this->iterator->valid()){
                return $this->iterator->next();
            }
        }
        // seek row
        public function seek($pos){
            if(!is_int($pos)||$pos<0){
                throw new Exception('Invalid position');
            }
            return $this->iterator->seek($pos);
        }
        // count rows
        public function count(){
            return $this->iterator->count();
        }
    }
    // implement 'ResultIterator'
    try{
        // 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());
        // reset pointer to beginning of result set
        $rIterator->rewind();
        // display current row of result set
        echo $rIterator->current();
        // move to next row of result set
        $rIterator->next();
        // display current row of result set
        echo $rIterator->current();
        // display number of rows in result set
        echo $rIterator->count();
        // move file pointer to third row in result set
        $rIterator->seek(3);
        // display third row in result set
        echo $rIterator->current();
    }
    catch(Exception $e){
        echo $e->getMessage();
        exit();
    }

    That's it. The above example shows a simple approach for traversing a MySQL dataset, after connecting to the server and fetching some rows from a hypothetical database table. Similar to the script I wrote for implementing the "FileIterator" class, all the methods for moving back and forth across the returned dataset are called in sequence. In addition, I listed the classes that connect to MySQL and fetch rows from the corresponding database table, therefore you can see how each class fits with each other. Quite simple, right?

    Wrapping up

    Unfortunately, this series has concluded now. If you've been reading each of the parts, then I hope you've acquired a deeper grounding in iterators in PHP 4/ PHP 5.

    With all the written examples, I demonstrated how to use the iterator pattern for traversing different data structures, that is arrays, flat files and MySQL result sets, by utilizing nearly the same sets of methods, which is a good approach to coding standard classes for accessing many data types. As for other design patterns, mastering them takes a while, so be patient and digest the concepts very slowly. The reward is really worth it!



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

       

    PHP ARTICLES

    - Implementing Factory Methods in PHP 5
    - Merging a File Split for FTP Upload using PHP
    - Getting Data from Yahoo Site Explorer Inboun...
    - Method Chaining: Adding More Selecting Metho...
    - How to Split a File During an FTP Upload Usi...
    - Expanding a Custom CodeIgniter Library with ...
    - Using the Yahoo Site Explorer Inbound Links ...
    - Building a CodeIgniter Custom Library with M...
    - Building an E-mini Trading System Using PHP ...
    - Completing the MySQL Class with Method Chain...
    - Building Dynamic Queries with Chainable Meth...
    - PHP Encryption and Decryption Methods
    - Building a MySQL Abstraction Class with Meth...
    - Completing a Sample String Processor with Me...
    - Mastering WHILE Loops for PHP and MySQL





    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 6 Hosted by Hostway
    For more Enterprise Application Development news, visit eWeek