PHP
  Home arrow PHP arrow Page 4 - Iterators in the Simplest Sense: Trave...
Dev Shed Forums 
Administration  
AJAX  
Apache  
BrainDump  
DHTML  
Flash  
Java  
JavaScript  
Multimedia  
MySQL  
Oracle  
Perl  
PHP  
Practices  
Python  
Reviews  
Security  
Style-Sheets  
Web Services  
XML  
Zend  
Zope  
Forums Sitemap 
IBM® developerWorks 
Sun Developer Network 
Dedicated Servers 
E-Commerce Hosting 
Linux Web Hosting 
Managed Hosting 
Small Business Hosting 
Moblin 
JMSL Numerical Library 
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? 
PHP

Iterators in the Simplest Sense: Traversing Data Structures in PHP 5
By: Alejandro Gervasio
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 4 stars4 stars4 stars4 stars4 stars / 6
    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:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb 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!


    DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.

       · This last tutorial of the series shows how to apply the Iterator pattern in PHP 5,...
       · The idea is great! I couldn't get it to work, however. Seems like the problem lies...
       · Thank you for reading and commenting on this PHP article. With reference to the...
     

       

    PHP ARTICLES

    - Validating Web Forms with the Code Igniter P...
    - Output Buffering
    - Paginating Database Records with the Code Ig...
    - HTTP Headers in Web Development
    - Project Management: Administration
    - Building a Database-Driven Application with ...
    - User Authentication for a Project Management...
    - Introduction to the CodeIgniter PHP Framework
    - Adding Users for a Project Management Applic...
    - Migrating Class Code for a MIME Email to PHP...
    - Login and Logout Authentication for a Projec...
    - Composing Messages in HTML for MIME Email wi...
    - Project Management: Authentication
    - A Better Way to Determine MIME Types for MIM...
    - Project Management Overview





    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 5 hosted by Hostway