/**
*这个文件包含类实现列表功能
*/
/**
*CList实现一个整数索引的集合类
* 你可以通过使用 itemAt,add,insertAt,remove,以及removeAt访问,添加,插入,删除项目。 通过getCount,你可以取得这个列表的项目数。 如下所示,CList也可以当作一般数组来使用:
*$list[]=$item; //在尾部添加
*$list[$index]=$item; //$index一定要在0和$list->Count之间
*unset($list[$index]); //删除指定$index的项目
*if(isset($list[$index])) //如果列表中存在$index指定的项目
*foreach($list as $index=>$item) //遍历列表中的项目
*$n=count($list); //返回列表中的项目数
*
*/
class CList implements IteratorAggregate,ArrayAccess,Countable
{
/**
* 数据仓库
*/
private $_d=array();
/**
* @var integer 存储数据
*/
private $_c=0;
/**
* @var boolean 列表是否只读
*/
private $_r=false;
/**
* 构造器,用一个数据或者一个可迭代的对象实例化列表(对象是否实现了,IteratorAggregate 或 Iterator接口)
* @param array $data 初始化数据。默认值是null,这意味着没有初始化.
* @param boolean $readOnly 列表是否为只读
* @throws Exception 如果数据不为空,且 即不是一个数组也不是一个迭代器时抛出Exception
*/
public function __construct($data=null,$readOnly=false)
{
if($data!==null)
$this->copyFrom($data);
$this->setReadOnly($readOnly);
}
/**
* @return boolean 列表是是否只读,true为只读,false可读,可写
*
*/
public function getReadOnly()
{
return $this->_r;
}
/**
* @param boolean $value 设置这个列表是否为只读
*/
protected function setReadOnly($value)
{
$this->_r=$value;
}
/**
* 返回遍历这个项目列表的迭代器。 此方法为接口IteratorAggregate强制要求实现。
* @return Iterator 一个迭代器,用于遍历列表中的条目
*/
public function getIterator()
{
return new CListIterator($this->_d);
}
/**
* 返回列表的项目数。
* 此方法为接口Countable强制要求实现。
*
* @return integer 列表项总数.
*/
public function count()
{
return $this->getCount();
}
/**
* 返回列表的项目数。
*
* @return integer 列表项总数
*/
public function getCount()
{
return $this->_c;
}
/**
* 返回指定位置的项目,这个方法跟offsetGet是完全一样的。
* @param integer $index 指定的索引
* @return mixed 索引对应的项
* @throws Exception 如果索引越界,刚抛出异常
*/
public function itemAt($index)
{
if(isset($this->_d[$index]))
return $this->_d[$index];
else if($index>=0 && $index_c) // in case the value is null
return $this->_d[$index];
else
throw new Exception("List index {$index} is out of bound.");
}
/**
* 在列表尾部添加一个项目。
*
* @param mixed $item 新项
* @return integer 添加项的索引值(索引基于零开始)
*/
public function add($item)
{
$this->insertAt($this->_c,$item);
return $this->_c-1;
}
/**
* 将项目插入到指定位置。 该位置的原项目及它后面的项目会依次后移
*
* @param integer $index 指定的位置.
* @param mixed $item 添加的项目
* @throws Exception 如果数据越界,或者该列表只读时
*/
public function insertAt($index,$item)
{
if(!$this->_r)
{
if($index===$this->_c)
$this->_d[$this->_c++]=$item;
else if($index>=0 && $index_c)
{
array_splice($this->_d,$index,0,array($item));
$this->_c++;
}
else
throw new Exception("List index {$index} is out of bound.");
}
else
throw new Exception('The list is read only.');
}
/**
* 从列表中删除一个项目。 这个列表首先会搜索这个项目。 在列表中第一个找到的项目会被删除。(也就是说, 列表中可能存在着相同的项目)
*
* @param mixed $item 要删除的项目.
* @return integer 删除项目的索引
* @throws Exception 如果该项目不存在
*/
public function remove($item)
{
if(($index=$this->indexOf($item))>=0)
{
$this->removeAt($index);
return $index;
}
else
return false;
}
/**
* 删除指定位置的项目。
* @param integer $index 要删除的项目索引
* @return mixed 删除的项目.
* @throws Exception 如果索引越界或者列表只读,则抛出异常
*/
public function removeAt($index)
{
if(!$this->_r)
{
if($index>=0 && $index_c)
{
$this->_c--;
if($index===$this->_c)
return array_pop($this->_d);
else
{
$item=$this->_d[$index];
array_splice($this->_d,$index,1);
return $item;
}
}
else
throw new Exception("List index {$index} is out of bound.");
}
else
throw new Exception('The list is read only.');
}
/**
* 删除列表中的所有项目
*/
public function clear()
{
for($i=$this->_c-1;$i>=0;--$i)
$this->removeAt($i);
}
/**
* 列表中是否包含这个项目。
* @param mixed $item 要查找的项目
* @return boolean 是否包含项目
*/
public function contains($item)
{
return $this->indexOf($item)>=0;
}
/**
* 返回项目在列表中的索引值(基于0)
*
* @param mixed $item 要查找的项目
* @return integer 项目所在的项目(基于0开始),-1表示不存在
*/
public function indexOf($item)
{
if(($index=array_search($item,$this->_d,true))!==false)
return $index;
else
return -1;
}
/**
* @return array 数组中的项目列表
*/
public function toArray()
{
return $this->_d;
}
/**
* 将迭代器中的数据复制到列表。
* 注意,列表中已经存在的数据会被首先删除。
*
* @param mixed $data 要复制的数据, 只能是数组或者继承于Traversable的对象。
* @throws Exception 如果数据不是一个数据,也不是一个可迭代对象.
*/
public function copyFrom($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
if($this->_c>0)
$this->clear();
if($data instanceof CList)
$data=$data->_d;
foreach($data as $item)
$this->add($item);
}
else if($data!==null)
throw new Exception('List data must be an array or an object implementing Traversable.');
}
/**
* 将迭代器的数据整合到map 新的数据会添加到已存在的数据后面。
* @param mixed $data 要合并的数据, 只能是数组或者继承于Traversable的对象.
* @throws Exception 如果数据不是一个数据,也不是一个可迭代对象.
*/
public function mergeWith($data)
{
if(is_array($data) || ($data instanceof Traversable))
{
if($data instanceof CList)
$data=$data->_d;
foreach($data as $item)
$this->add($item);
}
else if($data!==null)
throw new Exception('List data must be an array or an object implementing Traversable.');
}
/**
* 返回值说明列表中是否包含这个项目。 此方法为接口ArrayAccess强制要求实现。
*
* @param integer $offset 要检查的位置
* @return boolean
*/
public function offsetExists($offset)
{
return ($offset>=0 && $offset_c);
}
/**
* 返回当前位置的项目,此方法是接口ArrayAccess强制要求实现的
*
* @param integer $offset 要检索的位置
* @return mixed 返回该索引的项目。
* @throws Exception 如果该位置无效时则抛出异常
*/
public function offsetGet($offset)
{
return $this->itemAt($offset);
}
/**
* 在指定位置插入项目。 此方法为接口ArrayAccess强制要求实现。
*
* @param integer $offset 要设置项目的位置
* @param mixed $item 项目值
*/
public function offsetSet($offset,$item)
{
if($offset===null || $offset===$this->_c)
$this->insertAt($this->_c,$item);
else
{
$this->removeAt($offset);
$this->insertAt($offset,$item);
}
}
/**
* 删除指定位置的项目。
* 此方法为接口ArrayAccess强制要求实现。
*
* @param integer $offset 要删除项目的位置
*/
public function offsetUnset($offset)
{
$this->removeAt($offset);
}
}
class CListIterator implements Iterator
{
/**
* @var array 遍历的数据
*/
private $_d;
/**
* @var integer 索引的当前项
*/
private $_i;
/**
* @var integer 数据库的总数
*/
private $_c;
/**
* 构造方法
* @param array $data 遍历的数据
*/
public function __construct(&$data)
{
$this->_d=&$data;
$this->_i=0;
$this->_c=count($this->_d);
}
/**
* 重置当前数组索引位置。此方法为接口Iterator强制要求实现。
*/
public function rewind()
{
$this->_i=0;
}
/**
* 返回保存数据的数组中的当前键名。 此方法为接口Iterator强制要求实现。
* @return integer 当前数组项目的键名。
*/
public function key()
{
return $this->_i;
}
/**
* 返回保存数据的数组中的当前项目。
* 此方法为接口Iterator强制要求实现。
*
* @return mixed 返回当前数组项目
*/
public function current()
{
return $this->_d[$this->_i];
}
/**
* 移动当前索引到下一位置。
* 此方法为接口Iterator强制要求实现。
*/
public function next()
{
$this->_i++;
}
/**
* 返回值说明当前位置是否存在一个项目。
* 此方法为接口Iterator强制要求实现。
*
* @return boolean
*/
public function valid()
{
return $this->_i_c;
}
}
$data = array('a', 'b', 'c');
$list = new CList($data);
$list->insertAt(0, '0');
$list->insertAt(1, '1');
$list->insertAt(2, '2');
$list->insertAt(3, '3');
$list->removeAt(1);
foreach($list as $key=>$item) {
echo $key.'=>'.$item.'
';
}