Location: PHPKode > scripts > CSV Iterator > csv-iterator/CSVIterator.php
<?php
/**
 *	This package contains two classes for iterating over a csv file
 *	as though it were a native php array
 *
 *	@author Sam Shull <hide@address.com>
 *	@version 1.0
 *
 *	@copyright Copyright (c) 2009 Sam Shull <hide@address.com>
 *	@license <http://www.opensource.org/licenses/mit-license.html>
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *	
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *	
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 *
 *
 *	Changes:
 *		07/08/2009 - fix allow_calltime_pass_by_refererence errors
 *					 added CSVIterator::save method to enable copying of data to new file
 *					 added CSVIteratorRow::toArray
 *					 fixed CSVIterator::offsetSet
 *					 fixed CSVIterator::rewind to set CSVIterator::currentRow
 *					 set CSVIteratorRow::$saveChanges to true by default
 *
 */

require_once 'streamfunctions.php';

/**
 *
 *
 *	<code>
 *		$csv = new CSVIterator('code.csv');
 *
 *		$i = 0;
 *		
 *		foreach ($csv as $key => $row)
 *		{
 *			print "{$key}: {$i}: {$row[$i]}\n";
 *			$i += $i < count($row)-1 ? 1 : -$i;
 *		}
 *	</code>
 *
 */
class CSVIterator implements ArrayAccess, Iterator, Countable
{
	
	/*****************************************************************************************************************
	 *
	 *									properties
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@var resource
	 */
	protected $pointer;
	
	/**
	 *
	 *
	 *	@var string
	 */
	protected $filename;
	
	/**
	 *
	 *
	 *	@var array
	 */
	protected $lines;
	
	/**
	 *
	 *
	 *	@var array
	 */
	protected $currentRow;
	
	/**
	 *
	 *
	 *	@var integer
	 */
	public $length = 0;
	
	/**
	 *
	 *
	 *	@var string
	 */
	public $delimiter = ",";
	
	/**
	 *
	 *
	 *	@var string
	 */
	public $enclosure = '"';
	
	/**
	 *
	 *
	 *	@var string
	 */
	public $escape = '\\';
	
	/**
	 *
	 *
	 *	@var integer
	 */
	public $maxCount = 0;
	
	/**
	 *	A private function for indexing the contents
	 *	of the CSV file. Random line fetches perform faster.
	 *
	 */
	private function setup ()
	{
		rewind($this->pointer);
		//file should be locked during this time
		flock($this->pointer, LOCK_SH);
		
		$this->lines = array();
		$this->maxCount = 0;
		
		while (!feof($this->pointer))
		{
			$current 	= ftell($this->pointer);
			$arr		= version_compare(PHP_VERSION, "5.3", ">=") ? 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape) : 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);
							
			//end of csv is before eof
			if (false === $arr)
			{
				break;
			}
			
			$count		= count($arr);
			$this->lines[] = $current;
			
			//keep track of the 
			if ($count > $this->maxCount)
			{
				$this->maxCount = $count;
			}
		}
		
		rewind($this->pointer);
		//unlock file
		flock($this->pointer, LOCK_UN);
		$this->next();
		return;
	}
	
	/**
	 *
	 *
	 *
	 */
	public function normalize ()
	{
		rewind($this->pointer);
		//lock for writing
		flock($this->pointer, LOCK_EX);
		
		while (!feof($this->pointer))
		{
			$current 	= ftell($this->pointer);
			$arr		= version_compare(PHP_VERSION, "5.3", ">=") ? 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape) : 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);;
			$count		= count($arr);
			
			if ($count < $this->maxCount)
			{
				fseek($this->pointer, $current, SEEK_SET);
				fremovecsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);
				finsertcsv($this->pointer, array_pad($arr, $this->maxCount, ""), $this->delimiter, $this->enclosure);
			}
		}
		
		flock($this->pointer, LOCK_UN);
		$this->setup();
		$this->next();
		return;
	}
	
	/**
	 *	Save the Iterator to a new file
	 *
	 *	@param string $filename
	 *	@return integer | boolean
	 */
	public function save ($filename)
	{
		if ($f = fopen($filename, 'w'))
		{
			$tell = ftell($this->pointer);
			
			$this->rewind();
			
			foreach ($this as $row)
			{
				fwrite($f, strval($row) . "\n");
			}
			
			fclose($f);
			
			fseek($this->pointer, $tell, SEEK_SET);
			
			return filesize($filename);
		}
		
		return false;
	}
	
	/*****************************************************************************************************************
	 *
	 *									Magic methods
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@param string $file
	 *	@param integer $length = 0
	 *	@param string $delimiter = ,
	 *	@param string $enclosure = "
	 *	@param string $escape = \
	 */
	public function __construct ($file, $length=0, $delimiter=",", $enclosure='"', $escape='\\')
	{
		$this->filename 	= realpath((string)$file);
		$this->length 		= (int)$length;
		$this->delimiter 	= (string)$delimiter;
		$this->enclosure 	= (string)$enclosure;
		$this->escape		= (string)$escape;
		$this->pointer 		= fopen((string)$file, "a+");
		$this->setup();
	}
	
	/**
	 *	Close the pointer
	 *
	 *	
	 */
	public function __destruct ()
	{
		fclose($this->pointer);
	}
	
	/**
	 *	Get a row
	 *
	 *	@param integer $offset
	 *
	 *	@return string
	 */
	public function __get ($offset)
	{
		return $this->offsetGet($offset);
	}
	
	/**
	 *	Set a row
	 *
	 *	@param integer $offset
	 *	@param string $value
	 */
	public function __set ($offset, $value)
	{
		return $this->offsetSet($offset, $value);
	}
	
	/**
	 *	Check if a row is set
	 *
	 *	@param integer $offset
	 *	@return boolean
	 */
	public function __isset ($offset)
	{
		return $this->offsetExists($offset);
	}
	
	/**
	 *	Remove a row
	 *
	 *	@param integer $offset
	 */
	public function __unset ($offset)
	{
		return $this->offsetUnset($offset);
	}
	
	/**
	 *	Returns the entire file as a string
	 *
	 *	@return string
	 */
	public function __toString ()
	{
		$this->rewind();
		
		$str = "";
		
		foreach ($this as $row)
		{
			$str .= (string)$row;
		}
		
		return $str;
	}
	
	/**
	 *
	 *
	 *	@return array
	 */
	public function __sleep()
	{
		return array(
					"filename",
					"length",
					"delimiter",
					"enclosure",
					"escape",
					);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function __wakeup ()
	{
		$this->pointer = fopen($this->filename, "a+");
		$this->setup();
	}
	
	/*****************************************************************************************************************
	 *
	 *									ArrayAccess
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *	Get a row
	 *
	 *	@param integer|string $offset
	 *	@return string
	 */
	public function offsetGet ($offset)
	{
		if (strstr($offset, ","))
		{
			$pos = explode(",", $offset, 2);
			return $this->slice((int)$pos[0], intval($pos[1] ? $pos[1] : $this->count()));
		}
		
		if (!is_numeric($offset))
		{
			throw new InvalidArgumentException();
		}
		
		$n = $this->count();
		
		if ($offset > $n || $offset < 0)
		{
			throw new OutOfRangeException();
		}
		
		$current = ftell($this->pointer);
		
		fseek($this->pointer, $this->lines[$offset], SEEK_SET);
		
		$arr = version_compare(PHP_VERSION, "5.3", ">=") ? 
				fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape) : 
				fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);;
		
		fseek($this->pointer, $current, SEEK_SET);
		
		return new CSVIteratorRow($this, $offset, $arr);
	}
	
	/**
	 *	Set a row
	 *
	 *	@param integer $offset
	 *	@param array|CSVIteratorRow $value
	 */
	public function offsetSet ($offset, $value)
	{
		if (!(is_array($value) || $value instanceof CSVIteratorRow))
		{
			throw new InvalidArgumentException();
		}
		
		if ($offset < 0)
		{
			throw new OutOfRangeException();
		}
		
		$n = $this->count();
		
		$fields = is_array($value) ? new CSVIteratorRow($this, is_numeric($offset) ? $offset : $n, $value) : $value;
		
		if (!is_numeric($offset) || $offset >= $n)
		{
			return $this->append($fields->toArray());
		}
		
		$current = ftell($this->pointer);
		
		fseek($this->pointer, $this->lines[$offset], SEEK_SET);
		
		fremovecsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);
		
		finsertcsv($this->pointer, $fields->toArray(), $this->delimiter, $this->enclosure, $this->escape);
		
		$this->setup();
		
		fseek($this->pointer, $current, SEEK_SET);
		
		$this->next();
		
		return;
	}
	
	/**
	 *	Check if a row exists
	 *
	 *	@param integer $offset
	 *	@return boolean
	 */
	public function offsetExists ($offset)
	{
		return isset($this->lines[$offset]);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function offsetUnset ($offset)
	{
		if (!is_numeric($offset))
		{
			throw new InvalidArgumentException();
		}
		
		$n = $this->count();
		
		if ($offset > $n || $offset < 0)
		{
			throw new OutOfRangeException();
		}
		
		return $this->remove($offset);
	}
	
	/*****************************************************************************************************************
	 *
	 *									Countable
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return integer
	 */
	public function count ()
	{
		return count($this->lines);
	}
	
	/*****************************************************************************************************************
	 *
	 *									Iterator
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return boolean
	 */
	public function valid ()
	{
		return key($this->lines) !== null && is_array($this->currentRow);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function rewind ()
	{
		reset($this->lines);
		rewind($this->pointer);
		$this->currentRow = version_compare(PHP_VERSION, "5.3", ">=") ? 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape) : 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);
		return;
	}
	
	/**
	 *
	 *
	 *	@return integer
	 */
	public function key ()
	{
		return key($this->lines);
	}
	
	/**
	 *
	 *
	 *	@return CSVIteratorRow
	 */
	public function current ()
	{
		return new CSVIteratorRow($this, key($this->lines), $this->currentRow);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function next ()
	{
		next($this->lines);
		$this->currentRow = version_compare(PHP_VERSION, "5.3", ">=") ? 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape) : 
							fgetcsv($this->pointer, $this->length, $this->delimiter, $this->enclosure);
		return;
	}
	
	/*****************************************************************************************************************
	 *
	 *									useful additions
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return CSVIteratorRow
	 */
	public function prev ()
	{
		fseek($this->pointer, prev($this->lines), SEEK_SET);
		$this->next();
		return $this->current();
	}
	
	/**
	 *
	 *
	 *	@return CSVIteratorRow
	 */
	public function end ()
	{
		fseek($this->pointer, end($this->lines), SEEK_SET);
		$this->next();
		return $this->current();
	}
	
	/**
	 *
	 *
	 *
	 */
	public function reset ()
	{
		return $this->rewind();
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *
	 *	@return integer
	 */
	public function remove ($offset)
	{
		if (!isset($this->lines[$offset]))
		{
			throw new OutOfRangeException();
		}
		
		$current = ftell($this->pointer);
		
		fseek($this->pointer, $this->lines[$offset], SEEK_SET);
		
		$ret = fremovecsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape);
		
		$this->setup();
		
		fseek($this->pointer, $current, SEEK_SET);
		
		$this->next();
		
		return $ret;
	}
	
	/**
	 *
	 *
	 *	@param array $fields
	 *
	 *	@return integer
	 */
	public function append (array $fields)
	{
		$current = ftell($this->pointer);
		
		fseek($this->pointer, 0, SEEK_END);
		
		$count = count($fields);
		
		if ($count > $this->maxCount)
		{
			$this->maxCount = $count;
		}
		elseif ($count < $this->maxCount)
		{
			$fields = array_pad($fields, $this->maxCount, "");
			$count = count($fields);
		}
		
		$ret = version_compare(PHP_VERSION, "5.3", "<") ?
				fputcsv($this->pointer, $fields, $this->delimiter, $this->enclosure) :
				fputcsv($this->pointer, $fields, $this->delimiter, $this->enclosure, $this->escape);
		
		$this->lines[] = $current;
		
		fseek($this->pointer, $current, SEEK_SET);
		
		return $ret;
	}
	
	/**
	 *
	 *
	 *	@param array $fields
	 *
	 *	@return integer
	 */
	public function prepend (array $fields)
	{
		$current = ftell($this->pointer);
		
		fseek($this->pointer, 0, SEEK_SET);
		
		$ret = finsertcsv($this->pointer, $fields, $this->delimiter, $this->enclosure, $this->escape);
		
		$this->setup();
		
		fseek($this->pointer, $current, SEEK_SET);
		
		$this->next();
		
		return $ret;
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param array $fields
	 *
	 *	@return integer
	 */
	public function insert ($offset, array $fields)
	{
		if (!isset($this->lines[$offset]))
		{
			return $this->append($fields);
		}
		
		$current = ftell($this->pointer);
		
		fseek($this->pointer, $this->lines[$offset], SEEK_SET);
		
		$ret = finsertcsv($this->pointer, $fields, $this->delimiter, $this->enclosure, $this->escape);
		
		$this->setup();
		
		fseek($this->pointer, $current, SEEK_SET);
		
		$this->next();
		
		return $ret;
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function shift ()
	{
		$x = $this[0];
		$this->remove(0);
		return $x;
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function pop ()
	{
		$l = $this->count()-1;
		$x = $this[$l];
		$this->remove($l);
		return $x;
	}
	
	/**
	 *
	 *
	 *
	 */
	public function push ()
	{
		$args = func_get_args();
		$i = 0;
		foreach($args as $arg)
		{
			$this->append($arg);
			$i += 1;
		}
		return $i;
	}
	
	/**
	 *
	 *
	 *	@param mixed ...args
	 *
	 *	@return integer
	 */
	public function unshift ()
	{
		$args = func_get_args();
		$i = 0;
		foreach($args as $arg)
		{
			$this->prepend($arg);
			$i += 1;
		}
		return $i;
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param integer $length
	 *	@return array
	 */
	public function slice ($offset, $length=null)
	{
		if (!isset($this->lines[$offset]))
		{
			throw new OutOfRangeException();
		}
		
		$length = $length ? $length : $this->count();
		$ret = array();
		fseek($this->pointer, $this->lines[$offset]);
		
		while($length && !feof($this->pointer))
		{
			$ret[] = fremovecsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape);
			$length -= 1;
		}
		
		$this->setup();
		
		return $ret;
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param integer $length
	 *	@param array $replacement - should always be an array of arrays
	 *	@return array
	 */
	public function splice ($offset, $length, array $replacement)
	{
		if (!isset($this->lines[$offset]))
		{
			throw new OutOfRangeException();
		}
		
		reset($replacement);
		$ret = array();
		fseek($this->pointer, $this->lines[$offset]);
		
		while($length && !feof($this->pointer))
		{
			$ret[] = fremovecsv($this->pointer, $this->length, $this->delimiter, $this->enclosure, $this->escape);
			$length -= 1;
		}
			
		while ($replacement)
		{
			$insert = array_shift($replacement);
			if (!is_array($insert))
			{
				throw new InvalidArgumentException();
			}
			finsertcsv($this->pointer, $insert, $this->delimiter, $this->enclosure, $this->escape);
		}
		
		$this->setup();
		
		return $ret;
	}
	
	/*****************************************************************************************************************
	 *
	 *									Static methods
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@param array $arr
	 *	@param string $enclosure = "
	 *	@param string $escape = \
	 *
	 *	@return array
	 */
	public static function encapsulate (array $arr, $enclosure='"', $escape="\\")
	{
		$ret = array();
		foreach($arr as $element)
		{
			$ret[] = $enclosure . str_replace($enclosure, $escape . $enclosure, $element) . $enclosure;
		}
		return $ret;
	}
}

/**
 *
 *
 *
 */
class CSVIteratorRow implements ArrayAccess, Iterator, Countable
{
	/*****************************************************************************************************************
	 *
	 *									properties
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@var CSVIterator
	 */
	protected $csv;
	
	/**
	 *
	 *
	 *	@var integer
	 */
	protected $row;
	
	/**
	 *
	 *
	 *	@var array
	 */
	protected $_array;
	
	/**
	 *
	 *
	 *	@var boolean
	 */
	protected $saveChanges = true;
	
	/**
	 *
	 *
	 *
	 */
	public function normalize ()
	{
		if (count($this->_array) < $this->csv->maxCount)
		{
			$this->_array = array_pad($this->_array, $this->csv->maxCount, "");
		}
		return;
	}
	
	/*****************************************************************************************************************
	 *
	 *									Magic methods
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@param CSVIterator $csv
	 *	@param integer $row
	 *	@param array $_array
	 */
	public function __construct (CSVIterator $csv, $row, array $_array)
	{
		$this->csv = $csv;
		$this->row = $row;
		$this->_array = $_array;
		return;
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *
	 *	@return string
	 */
	public function __get ($offset)
	{
		return $this->_array[$offset];
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param string $value
	 *
	 *	@return boolean
	 */
	public function __set ($offset, $value)
	{
		return $this->offsetSet($offset, $value);
	}
	
	/**
	 *
	 *
	 *	@return boolean
	 */
	public function __isset ($offset)
	{
		return $this->offsetExists($offset);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function __unset ($offset)
	{
		return $this->offsetUnset($offset);
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function __toString ()
	{
		return implode($this->csv->delimiter, CSVIterator::encapsulate($this->_array, $this->csv->enclosure, $this->csv->escape));
	}
	
	/*****************************************************************************************************************
	 *
	 *									ArrayAccess
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *
	 *	@return string
	 */
	public function offsetGet ($offset)
	{
		return $this->_array[$offset];
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param string $value
	 */
	public function offsetSet ($offset, $value)
	{
		if (!isset($this->_array[$offset]) || $this->_array[$offset] != $value)
		{
			$this->_array[$offset] = strval($value);
			$this->update();
		}
		return;
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *
	 *	@return boolean
	 */
	public function offsetExists ($offset)
	{
		return isset($this->_array[$offset]);
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 */
	public function offsetUnset ($offset)
	{
		unset($this->_array[$offset]);
		$this->normalize();
		$this->update();
		return;
	}
	
	/*****************************************************************************************************************
	 *
	 *									Countable
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return integer
	 */
	public function count ()
	{
		return count($this->_array);
	}
	
	/*****************************************************************************************************************
	 *
	 *									Iterator
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return boolean
	 */
	public function valid ()
	{
		return key($this->_array) !== null;
	}
	
	/**
	 *
	 *
	 *	@return boolean
	 */
	public function rewind ()
	{
		return reset($this->_array);
	}
	
	/**
	 *
	 *
	 *	@return integer
	 */
	public function key ()
	{
		return key($this->_array);
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function current ()
	{
		return current($this->_array);
	}
	
	/**
	 *
	 *
	 *	@return boolean
	 */
	public function next ()
	{
		return next($this->_array);
	}
	
	/*****************************************************************************************************************
	 *
	 *									useful additions
	 *	
	/*****************************************************************************************************************/
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function prev ()
	{
		return prev($this->_array);
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function end ()
	{
		return end($this->_array);
	}
	
	/**
	 *
	 *
	 *
	 */
	public function reset ()
	{
		return $this->rewind();
	}
	
	/**
	 *
	 *
	 *	@param string $element
	 *
	 *	@return boolean
	 */
	public function remove ($offset)
	{
		return $this->offsetUnset($offset) || true;
	}
	
	/**
	 *
	 *
	 *	@param string $element
	 *
	 *	@return integer
	 */
	public function append ($element)
	{
		return $this->unshift($element);
	}
	
	/**
	 *
	 *
	 *	@param string $element
	 *
	 *	@return integer
	 */
	public function prepend ($element)
	{
		return $this->push($element);
	}
	
	/**
	 *
	 *
	 *	@param integer $offset
	 *	@param string $element
	 */
	public function insert ($offset, $element)
	{
		return $this->offsetSet($offset, $element);
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function shift ()
	{
		$x = array_shift($this->_array);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *	@return string
	 */
	public function pop ()
	{
		$x = array_pop($this->_array);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *	@param mixed ...args
	 *
	 *	@return integer
	 */
	public function push ()
	{
		$args = func_get_args();
		array_unshift($args, $this->_array);
		$x = call_user_func_array("array_push", $args);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *	@param mixed ...args
	 *
	 *	@return integer
	 */
	public function unshift ()
	{
		$args = func_get_args();
		array_unshift($args, $this->_array);
		$x = call_user_func_array("array_unshift", $args);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *	@param mixed ...args
	 *
	 *	@return mixed
	 */
	public function slice ($offset/*, $length=null*/)
	{
		$args = func_get_args();
		array_unshift($args, $this->_array);
		$x = call_user_func_array("array_slice", $args);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *	@param mixed ...args
	 *
	 *	@return mixed
	 */
	public function splice ($offset, $length/*, $replacement=null*/)
	{
		$args = func_get_args();
		array_unshift($args, $this->_array);
		$x = call_user_func_array("array_splice", $args);
		$this->update();
		return $x;
	}
	
	/**
	 *
	 *
	 *
	 */
	public function update ()
	{
		if ($this->saveChanges)
		{
			$this->normalize();
			return $this->csv->offsetSet($this->row, $this->_array);
		}
	}
	
	/**
	 *
	 *
	 *
	 */
	public function toArray ()
	{
		return $this->_array;
	}
}

?>
Return current item: CSV Iterator