$array = array(
'n1' => 'andrew',
'n2' => 'Delia',
'n3' => 'Qiqi',
);
foreach ($array as $key => $name) {
echo "key=$key,name=$name".PHP_EOL;
}
我们把这种可遍历的特征,叫做可迭代。并且,这里我们很有必要介绍一下,在遍历一个数组的时候,它的基本过程应该是什么?首先我们来了解一下几个关于数组指针的操作方法。
reset():将数组指针移至第一个元素位置
next():将数组指针移到下一个元素
key():获取当前元素的key
current():获取当前元素的值
有了这几个方法后,就可以很好地解释foreach的实现方式了。首先,用reset()将指针移至数组第一个元素位置。其次,分别使用key(), current()方法获取当前元素的key和值。最后调用next()移到下一个元素,以此类推便可将所有元素遍历完成。
那么对于数组如此?如果是一个对象呢?能不能像数组一样被遍历呢?答案,显然是可以的。PHP内核为面向对象用户们在系统内就内置了一个Iterator接口。实现此接口的类对象就可以被遍历。那么,这个接口规定了哪些方法是必须实现的呢?我们来看下手册中对Iterator的定义:
Iterator extends Traversable {
abstract public mixed current ( void )
abstract public scalar key ( void )
abstract public void next ( void )
abstract public void rewind ( void )
abstract public boolean valid ( void )
}
先不要管这个Traversable,因为它只是一个空接口,无需实现任何方法。我们可以看到,系统规定,要实现Iterator接口就必须实现current(), key(), next(), rewind(), valid()方法.我们不自主就会想到,这不就和数组遍历所需要的那几个方法对应么?current(),key(),next()是一样的。rewind()其实就对应于reset().只多出来一个valid().这个valid()方法是做什么用的呢?我们知道,数组里面,只要有元素,那它肯定是有效元素,所以在遍历数组各元素的时候,它无需判断这个元素是否有效。但对于对象来说就不一样了,我们为了满足业务的需要,对象里的一些元素可能是不希望被用户遍历的,或者有些元素就有问题。那么每次获取元素值或key时都会用valid()方法来判断当前元素是否有效。那既然如此。我们只要定义一个类,实现了这些方法,系统就会自行调用相应的方法帮我们实现对象的遍历。那我们举个例子,在一个对象中訸一个数组。当遍历对象时,就遍历这个数组。代码如下:
class Test implements Iterator {
protected $_data = array();
public function __construct()
{
$this->_data = array(
'key1' => 1,
'key2' => 2,
);
}
public function rewind()
{
reset($this->_data);
}
public function current()
{
return current($this->_data);
}
public function next()
{
return next($this->_data);
}
public function valid()
{
return (key($this->_data) !== null);
}
public function key()
{
return key($this->_data);
}
}
$test = new Test();
foreach ($test as $key => $value) {
echo "key:$key,value:$value".PHP_EOL;
}
输出结果为:
key:key1,value:1
key:key2,value:2
那么对于类对象的这种可迭代特征的实现,我们叫做迭代器模式。简单地说,就是类对象可遍历。很简单吧?