Iterators in the Simplest Sense: Traversing Different Data Structures - More iterators ahead: creating a MySQL result set iterator class (
Page 4 of 4 )
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!
| | Discuss Iterators in the Simplest Sense: Traversing Different Data Structures | | | | | | | In this second article, the Iterator pattern is applied to the development of... | | | | | | Thanks. Learned a thing or two again. Nice to see how the base class can be extended... | | | | | | Hi Matthijs,
Thanks again for keeping yourself reading my PHP articles, and of... | | | | | | Hi Matthijs,
The code has been corrected. Again, thanks for spotting... | | | | | | Thank you Charles for correcting the code of the article. I truly appreciate that.... | | | | | | "I'll provide you with a concise explanation of what an Iterator is, in conjunction... | | | | | | Hello Matthijs,
Thank you again for commenting on this article, as well as for... | | | | | | Id love to see you write a indepth series on AJAX. | | | | | | Dear Jonathan,
I'd like to thank you for your compliments on this tutorial, and... | | | | | | Thanks for taking the time to reply Alejandro. Appreciated.
Keep up the great... | | | | | | You're very welcome Matthijs. Thank you for your feedback and kind... | | | | | | >>> Post your comment now! | | | | | |
|