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";
}

<輸出>


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";
}

<輸出>


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:翻譯的是狗屁水平)

******************轉載請註明來源 ***************


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章