Iterator

From DreamHost
Jump to: navigation, search

This guide describes the using the PHP SPL Iterator. Iterators are also part of C++ and other languages, used to describe the action of looping over contents. Knowledge of C++ isn't required to use this guide.

The Iterator allows you to use foreach to iterate or loop over contents instead of using while.

SQLite and Iterator

The purpose of this example is to take another class that already implements Iterator and use its own Iterator for yourself. The reason you would do this is that if you do have an class that uses SQLite, you'll want to set your Iterator implementation to output the correct key and value.

Using IteratorAggregate Instead

foreach($myClass as $key => $value)
{
	echo 'Key: '. $key ."<br />\n Value: ". $value ."<br />\n";
}

Using SPL IteratorAggregate instead of Iterator will output a number for the key and the value will be an array. This is unacceptable, unless we have more than two elements, then we will want value to be an array, but the choice should be the developers.

Cannot Extend SQLite Class

You can not extend SQLite as it is set to final, restricting that ability. They must have some reason for restricting this functionality.

Example

References to other sites:

  1. http://www.sitepoint.com/print/php5-standard-library
  2. http://www.phpriot.com/d/articles/php/oop/oop-with-spl-php-5-1/page6.html
  3. Comments in PHP SPL Iterator page for constructor and init().
class ConfigTable implements Iterator
{	
	private $handle;
	private $database = 'Configuration.sqlite';
	private $table;
	
	private $name	= 'config_name';
	private $value	= 'config_value';
	
	// For Iterator, has all of the config in an array.
	private $Iterator;
	
	function __construct($table)
	{
		$path = realpath(dirname($_SERVER['DOCUMENT_ROOT']).'/sqlite');
		$this->database = rtrim($path .'/'. $this->database);
		$this->table = $table;
		$this->init();
	}
	
	private function init()
	{
		$this->handle = new SQLiteDatabase($this->database, 0660, $sqliteError);
		
		// Test to see if Database Exists.
		if(!file_exists($this->database) or !empty($sqliteError))
			throw new Exception("Couldn't Connect to Database: $sqliteError");
		
		// Test to see if Table Exists and create it if it doesn't.
		$testtable = $this->handle->query("SELECT name FROM sqlite_master WHERE type='table' AND name='". $this->table ."'");
		if($testtable->numRows() == 0)
		{
			$this->handle->queryExec("CREATE TABLE ". $this->table ." (". $this->name ." PRIMARY KEY, ". $this->value .")");
		}
		
		$this->Iterator = $this->handle->query("SELECT * FROM ". $this->table);
	}
	
	// Begin Iterator
	function current()
	{
		$result = $this->Iterator->current(SQLITE_ASSOC);
		return $result['config_value'];
	}
	
	function key()
	{
		$result = $this->Iterator->current(SQLITE_ASSOC);
		return $result['config_name'];
	}
	
	function next()
	{
		return $this->Iterator->next();
	}
	
	function rewind()
	{
		return $this->Iterator->rewind();
	}
	
	function valid()
	{
		return $this->Iterator->valid();
	}
	// End Iterator
}

The __construct and init() functions are from another source. They just set up the database and the table. Do this however you wish.

The main details are in the following functions in between the Iterator Comments

  • valid()
  • rewind()
  • next()
  • key()
  • current()

There is an issue with using SQLiteResult::key(), it will return an error if you try to use it.

The only thing to mess with to fix the key and value is key() and current() methods. SQLiteResult::current returns the current result array, which allows us to not worry about checking the row. It will go to the next row handled by the next method. Simple and has little overhead.

Using this we can set up whatever field we want to use as the key in the myClass::key() and then have the rest as the values in the myClass::current().