Php-SPL库中的迭代器接口详解

SPL库中的迭代器接口

SPL提供了6个迭代器接口,如下表

Traversable 遍历接口(检测一个类是否可以使用 foreach 进行遍历的接口)
Iterator 迭代器接口(可在内部迭代自己的外部迭代器或类的接口)
IteratorAggregate 聚合式迭代器接口(创建外部迭代器的接口)
OuterIterator 迭代器嵌套接口(将一个或多个迭代器包裹在另一个迭代器中)
RecursiveIterator 递归迭代访问接口(提供递归访问功能)
SeekableIterator 可索引迭代访问接口(实现查找功能)

1、Traversable接口

Traversable接口实际上不是一个接口,在实际写php代码中不能用。因为只有内部的PHP类(用C写的类)才可以直接实现Traversable接口。可以说这是个特性级别的东西。实际的PHP编程中我们使用Iterator接口或者IteratorAggregate接口来实现遍历。

2、Iterator接口

 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)
    //判断当前索引游标指向的是否是一个元素,常常在调用 rewind()或 next()使用
    abstract public boolean valid(void)
}

【Iterator使用实例】

<代码>

class myIterator implements Iterator
{
    //索引游标
    private $position = 0;
    private $array = array(
        "第1个元素",
        "第2个元素",
        "最后1个元素",
    );

    public function __construct()
    {
        $this->position = 0;
    }

    function rewind()
    {
        echo "调用rewind方法\n";
        $this->position = 0;
    }

    function current()
    {
        echo "调用current方法\n";
        return $this->array[$this->position];
    }

    function key()
    {
        echo "调用key方法\n";
        return $this->position;
    }

    function next()
    {
        echo "调用next方法\n";
        ++$this->position;
    }

    function valid()
    {
        echo "调用valid方法\n";
        return isset($this->array[$this->position]);
    }
}

$it = new myIterator;
$times = 0;
foreach ($it as $key => $value) {
    $times ++;
    echo "键名:{$key}  值:{$value}\n";
    echo "----------第{$times}遍历完成--------->\n";
}

<输出>

Php-SPL库中的迭代器接口详解_第1张图片

3、IteratorAggregate接口

创建外部迭代器的接口,在文章《Php设计模式之迭代器模式Iterator Pattern(一) 》中介绍的迭代器就是这种。

【IteratorAggregate接口摘要】

IteratorAggregate extends Traversable {
//实现该方法时,必须返回一个实现了Iterator接口的类的实例
abstract public Traversable getIterator ( void )
}

SPL还提供了一些专门用来与IteratorAggregate接口一起使用的内置迭代器。使用这些迭代器意味着只需要实现一个方法并实例化一个类就可以使对象可以迭代访问了。

【Iterator使用实例】使用IteratorAggregate接口与ArrayIterator迭代器类输出类中公共属性

<代码>

class myData implements IteratorAggregate
{
    public $property1 = "公共属性1";
    public $property2 = "公共属性2";
    public $property3 = "公共属性3";

    public function __construct()
    {
        $this->property4 = "最后一个公共属性";
    }

    public function getIterator()
    {
        return new ArrayIterator($this);
    }
}

$obj = new myData;
foreach ($obj as $key => $value) {
    echo "键名:{$key}  值:{$value}\n";
}

<输出>

Php-SPL库中的迭代器接口详解_第2张图片

4、OuterIterator接口

迭代器嵌套接口(将一个或多个迭代器包裹在另一个迭代器中)

【OuterIterator接口摘要】

OuterIterator extends Iterator {
/* 方法 */
public Iterator getInnerIterator ( void )
/* 继承Iterator 的方法 */
abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

这个接口与IteratorAggregate接口的区别在于增加了 getInnerIterator方法。getInnerIterator方法返回当前正在迭代访问的迭代器。

【OuterIterator的使用】

这一接口与其它几个更加专用的迭代器的基础接口,其中包括AppendIterator、CachingIterator、FilterIterator、teratorIterator、LimitIterator、RecursiveIteratorIterator。

5、RecursiveIterator接口

RecursiveIterator接口提供了递归迭代访问功能,这种接口可以描述一个树形的数据结构,其中包含了节点\叶子或者父\子元素。它继承了Iterator界面,因而也具有标准的current()、key()、next()、 rewind()和valid()方法。同时,它自己还规定了getChildren()和hasChildren()方法。

【RecursiveIterator接口概要】

RecursiveIterator extends Iterator {
/* 方法 */
public RecursiveIterator getChildren ( void )
public bool hasChildren ( void )
/* 继承的方法 */
abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

【RecursiveIterator接口示例】递归遍历多维数组

<代码>

class MyRecursiveIterator implements RecursiveIterator
{
    private $_data;
    private $_position = 0;

    public function __construct(array $data)
    {
        $this->_data = $data;
    }

    public function valid()
    {
        return isset($this->_data[$this->_position]);
    }

    public function hasChildren()
    {
        return is_array($this->_data[$this->_position]);
    }

    public function next()
    {
        $this->_position++;
    }

    public function current()
    {
        return $this->_data[$this->_position];
    }

    public function getChildren()
    {
        print_r($this->_data[$this->_position]);
    }

    public function rewind()
    {
        $this->_position = 0;
    }

    public function key()
    {
        return $this->_position;
    }
}

$arr = array(
    0, 1, 2, 3, 4,
    5 => array(10, 20, 30), 6, 7, 8,
    9 => array(1, 2, 3)
);
$mri = new MyRecursiveIterator($arr);
foreach ($mri as $c => $v) {
    if ($mri->hasChildren()) {
        echo "第{$c}个元素含有子元素: \n";
        $mri->getChildren();
    } else {
        echo "第{$c}个元素:$v \n";
    }
}


<输出>


6、 SeekableIterator接口

SeekableIterator接口也是Iterator接口的延伸,除了Iterator的5个方法以外,还规定了seek()方法,参数是元素的位置,返回该元素。如果该位置不存在,则抛出OutOfBoundsException。

【SeekableIterator接口概要】

SeekableIterator extends Iterator {
/* 方法 */
abstract public void seek ( int $position )
/* 继承的方法 */
abstract public mixed Iterator::current ( void )
abstract public scalar Iterator::key ( void )
abstract public void Iterator::next ( void )
abstract public void Iterator::rewind ( void )
abstract public boolean Iterator::valid ( void )
}

【SeekableIterator接口示例】如何创建的的定制的SeekableIterator接口,并处理无效的游标异常。

<代码>

class MySeekableIterator implements SeekableIterator
{

    private $position = 0;
    private $array = array(
        "元素1",
        "元素2",
        "元素3",
        "元素4"
    );
    /**
     * Seek方法实现
     * @param $position
     * @throws OutOfBoundsException
     */
    public function seek($position)
    {
        $this->position = $position;
        if (!$this->valid()) {
            throw new OutOfBoundsException("invalid seek position ($position)");
        }
    }

    /* Iterator接口中实现的方法 */
    public function __construct()
    {
        $this->position = 0;
    }

    public function rewind()
    {
        $this->position = 0;
    }

    public function current()
    {
        return $this->array[$this->position];
    }

    public function key()
    {
        return $this->position;
    }

    public function next()
    {
        ++$this->position;
    }

    public function valid()
    {
        return isset($this->array[$this->position]);
    }
}

try {
    $it = new MySeekableIterator;
    echo $it->current(), "\n";
    $it->seek(2);
    echo $it->current(), "\n";
    $it->seek(1);
    echo $it->current(), "\n";
    $it->seek(10);
} catch (OutOfBoundsException $e) {
    echo "无效游标位置:".$e->getMessage();
}

<输出>

php标准库(SPL库)中的迭代器接口目前至php5.3.13版本就提供了这些。


********************************************

* 作者:叶文涛 

* 标题:Php设计模式之迭代器模式Iterator Pattern(二)SPL库中的迭代器接口详解

* 参考:

*  php手册http://php.net/manual/en/spl.iterators.php

*《PHP高级程序设计:模式、框架和测试》 Kevin McArthur 著 汪泳 等译

*《PHP设计模式》Aaron Saray等著,梁志敏等译(PS:翻译的是狗屁水平)

******************转载请注明来源 ***************


你可能感兴趣的:(Php-SPL库中的迭代器接口详解)