Hello fellow PHP Builders,

I just wrote up a class to iterate over a CSV file and would like come comments so that I can improve it and make it more useful. Right now it does what I need but I would like to make it better for the PHP community as a whole.

I am only going to post the class here but if you wish to see usage and examples (and downloads) please see my site http://white-box.us.

Here it is in all its glory:

/**
* Class: CSVIterator
* Desc: Read a CSV file
* @author: Raymond J Kolbe
* @copyright: July 10th, 2007
*/
class CSVIterator extends ArrayIterator{
	private $csvFile;		  // the location to our file
	private $colseparator;  // the column separator
	private $csvData;		// The array iterator object
	/**
	* @param $file The csv file we wish to parse
	* @param $colseparator The column separator for data. Defaults to "," (comma)
	* @return void
	*/
	public function __construct($file, $colseparator = ","){
		if(!self::isValidFile($file)){
			throw new Exception("File is not valid!");
		}
		$this->csvFile = $file;
		$this->colseparator = $colseparator;
		// Get and pass our array of data to ArrayIterator
		parent::__construct(self::genCsvArray());
	}
	/**
	* @return An array of the lines from our csv file.
	* @throws Exception
	*/
	private function genCsvArray(){
		$lines = @file($this->csvFile, FILE_SKIP_EMPTY_LINES);
		if(!$lines){
			throw new Exception("Unable to pull lines into array.");
		}
		return $lines;
	}
	/**
	* @param $file The file in question
	* @return boolean True if the file is a file or false if it is not a valid file.
	*/
	public static function isValidFile($file){
		return (is_file($file));
	}
	/**
	* @return Void
	* @desc: Moves our array pointer forward.
	*/
	public function moveForward(){
		parent::next();
	}
	/**
	* @return array The next row in our file with each column as its own key
	*/
	public function getDataRow(){
		return explode($this->colseparator, parent::current());
	}
	/**
	* @return boolean Returns true if there is still data in the array, false if there is nothing
	*/
	public function hasData(){
		return (parent::valid());
	}
}

    I'd recommend using the [man]fgetcsv/man function to read the CSV file, rather than using file() and then using explode() to break lines into fields. The CSV file protocol is a bit more complex than just splitting on commas, and fgetcsv() is cognizant of that protocol; namely that if a field contains a comma and/or a double-quote, then the field must be quoted with double-quotes and any double-quotes that are part of the field data must be doubled up:

    field 1,"field 2 has ""quotes"", and it has a comma",this is field 3
    

      Nice NogDog. I didn't even know about that function...not that I really searched for one or thought there would be issues using file()

      Thank you. 🆒

        So I decided (and was originally deciding) to implement Iterator instead of extending ArrayIterator since there are additional methods I don't even need from ArrayIterator.

        While thinking about how to write this up, I did a search (and like I said before, I did not do before) and found what I believe to be the best code for performing tasks on a CSV file.

        Here is the new code, based on code from mortanon at gmail dot com from php.net (http://www.php.net/manual/en/function.fgetcsv.php#57802).

        All I ended up changing was the constructor:

        public function __construct($file, $delimiter=','){
        	if(!is_readable($file)){
        		throw new CSVException("File <".$file."> could not be read.");
        	}
        	$this->filePointer = @fopen($file, "r");
        	$this->delimiter = $delimiter;
        }
        

        And creating a destruct:

        function __destruct(){
        		fclose($this->filePointer); 
        }
        
          Write a Reply...