## Iterator界面
> 本段內容來自阮一峰老師再加自己的部分注解
SPL規定,所有部署了Iterator界面的class,都可以用在foreach Loop中。Iterator界面中包含5個必須部署的方法:
* current()
This method returns the current index's value. You are solely
responsible for tracking what the current index is as the
interface does not do this for you. (返回當前索引值)
* key()
This method returns the value of the current index's key. For
foreach loops this is extremely important so that the key
value can be populated. (返回當前的索引key)
* next()
This method moves the internal index forward one entry. (迭代中的內部指針往前進一步)
* rewind()
This method should reset the internal index to the first element. (重置迭代中的內部指針)
* valid()
This method should return true or false if there is a current
element. It is called after rewind() or next(). (驗證內部指針是否到最后一行)
**Example**
```
class ArrayReloaded implements Iterator {
/**
* 如前一篇文章所說,該類實現了Iterator接口,所以該類對象就是ZEND_ITER_OBJECT,對于ZEND_ITER_OBJECT的類對象,會通過調用對象實現的Iterator接口相關函數來進行foreach。
*/
private $array = array();
private $valid = FALSE;
function __construct($array) {
$this->array = $array;
}
function rewind(){
/**
* reset: 將數組的內部指針指向第一個單元,如果數組為空則返回false;
* 所以下述語句表示: 數組不為空并且已重置到第一個單元;
*/
$this->valid = (FALSE !== reset($this->array));
}
function current(){
return current($this->array);
}
function key(){
return key($this->array);
}
function next(){
/**
* next: 將數組中的內部指針向前移動一位
* 返回數組內部指針指向的下一個單元的值,或當沒有更多單元時返回 FALSE。
* 所以下述語句表示: 如果還有下一個單元的話,指針移動到下個單元并返回true;
*/
$this->valid = (FALSE !== next($this->array));
}
function valid(){
return $this->valid;
}
#↑↑ 以上5個方法是必須實現的接口方法,也可以再擴展prev和end等方法,后續會介紹一些SPL內置的實現了itertor接口的類,這些類可以拿來直接使用
}
$arr = array(
'color1' => 'red',
'color2' => 'blue',
'color3' => 'green',
'color4' => 'plack',
'color5' => 'purple'
);
$colors = new ArrayReloaded($arr);
# 通過foreach來遍歷
foreach($colors as $k => $v){
echo $k.':'.$v.'<br />';
}
# 通過while來遍歷
/**
* 1: foreach的內部實現方式其實也是如此,事實上直接用while來遍歷性能更高
* 2: 在使用迭代器來遍歷的時候,一定要記住要rewind和next,而PHP的foreach遍歷早已把rewind和next給集成了;
*/
echo '<hr />';
$colors -> rewind();
while($colors -> valid()){
echo $colors -> key().':'.$colors -> current().'<br />';
$colors -> next();
}
```
## ArrayIterator
```
ArrayIterator implements ArrayAccess , SeekableIterator , Countable , Serializable
```
這是一個非常有用的迭代器,里面實現了排序,添加,篩選等foreach不能直接實現的方法(*都是要全部遍歷出來再進行判斷處理,代碼不優雅維護性差*)
**Example**
```
<?php
$arr = array(
'color1' => 'red',
'color3' => 'green',
'color4' => 'plack',
'color2' => 'blue',
'color5' => 'purple'
);
// $colors = new ArrayIterator($arr); //可以直接通過實例一個數組迭代器對象,然后while這個迭代器;
//但以下的方式要更易于擴展
//先實例一個array對象
$colorsObj = new ArrayObject($arr);
$it = $colorsObj -> getIterator(); //獲得當前的ArrayIterator
# 通過while來遍歷
$it -> rewind();
while($it -> valid()){
echo $it -> key().':'.$it -> current().'<br />';
$it -> next();
}
#通過iterator迭代器來遍歷就變得很靈活
echo $colorsObj -> count(); //元素數量統計
//從第三個開始遍歷
$it -> rewind(); //凡是要使用迭代器之前先重置;
if($it -> valid()){
$it -> seek(2); //從0開始的,第二個位置
while($it -> valid()){
echo $it -> key().':'.$it -> current().'<br />';
$it -> next();
}
}
//對索引名進行升序排列
$it -> ksort();
foreach($it as $k => $v){
echo $k .'-->'. $v.'<br />';
}
//對索引值進行排序
$it -> asort();
foreach($it as $k => $v){
echo $k .'-->'. $v.'<br />';
}
//這些對象方法是否很熟悉? 這就是上一篇文章中說到的 "SPL是一種使object(物體)模仿array(數組)行為的interfaces和classes"
```
## AppendIterator
按順序迭代訪問幾個不同的迭代器。例如,希望在一次循環中迭代訪問兩個或者更多的組合。這個迭代器的append方法類似于array_merge()函數來合并數組。
**Example**
```
$arr1 = array(
'color1' => 'red',
'color3' => 'green',
'color4' => 'plack',
'color2' => 'blue',
'color5' => 'purple'
);
$arr2 = array(
'fruit1' => 'apple',
'fruit2' => 'orange',
'fruit3' => 'banana',
'fruit4' => 'grape',
'fruit5' => 'strawberry',
);
$ao1 = new ArrayIterator($arr1);
$ao2 = new ArrayIterator($arr2);
$iterator = new AppendIterator();
$iterator -> append($ao1);
$iterator -> append($ao2);
foreach($iterator as $k => $v){
echo $k.':'.$v,'<br>';
}
```
## MultipleIterator
迭代器的鏈接器,更多參考連接 http://php.net/manual/en/class.multipleiterator.php
```
$person_id = new ArrayIterator(array('001', '002', '003'));
$person_name = new ArrayIterator(array('張三', '李四', '王五'));
$person_age = new ArrayIterator(array(22, 23, 11));
$mit = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$mit->attachIterator($person_id, "ID");
$mit->attachIterator($person_name, "NAME");
$mit->attachIterator($person_age, "AGE");
echo"連接的迭代器個數:".$mit->countIterators() . "\n"; //3
foreach ($mit as $person) {
print_r($person);
}
/**output
Array
(
[ID] => 001
[NAME] => 張三
[AGE] => 22
)
Array
(
[ID] => 002
[NAME] => 李四
[AGE] => 23
)
Array
(
[ID] => 003
[NAME] => 王五
[AGE] => 11
)
**/
```
## LimitIterator
返回給定數量的結果以及從集合中取出結果的起始索引點
```
<?php
//相當于sql中的limit
$fruitArr = array(
'apple',
'banana',
'cherry',
'damson',
'elderberry'
);
$fruits = new ArrayIterator($fruitArr);
//從第一個開始取三個
foreach (new LimitIterator($fruits, 0, 3) as $fruit) {
var_dump($fruit);
}
//從第二個開始取到結束
foreach (new LimitIterator($fruits, 2) as $fruit) {
print_r($fruit);
}
/**output
string(5) "apple"
string(6) "banana"
string(6) "cherry"
cherrydamsonelderberry
*/
```
## FilterIterator
基于OuterIterator接口,用于過濾數據,返回符合條件的元素。必須實現一個抽象方法accept(),此方法必須為迭代器的當前項返回true或false
```
class UserFilter extends FilterIterator{
private $userFilter;
public function __construct(Iterator $iterator , $filter){
parent::__construct($iterator);
//要過濾的參數
$this->userFilter = $filter;
}
public function accept(){
/*
* getInnerIterator(): 獲得內部的迭代器
* current(): 然后獲取當前的元素
* in strcmp(string str1,string str2) 區分字符串中字母大小寫地比較,返回0就相同
* int strcasecmp(string str1,string str2) 忽略字符串中字母大小寫地比較,返回0就相同
* 如果accept返回false的話就過濾掉
*/
$user = $this->getInnerIterator()->current();
if (strcasecmp($user['name'] , $this->userFilter) == 0) {
return false;
}
return true;
}
}
$array = array (array ('name' => 'Jonathan' , 'id' => '5') , array ('name' => 'Abdul' , 'id' => '22'),array ('name' => 'zhouzhou' , 'id' => '9'));
$object = new ArrayObject($array);
//去除掉名為abdul的人員
$iterator = new UserFilter($object->getIterator() , 'abdul');
foreach ($iterator as $result) {
echo $result['name'];
}
/**output
* Jonathan
**/
```
## RegexIterator
繼承FilterIterator,支持使用正則表達式模式匹配和修改迭代器中的元素。經常用于將字符串匹配。
更多參考: http://cn2.php.net/manual/zh/class.regexiterator.php
```
//可以實現: preg_match_all(), preg_match(), preg_replace(),preg_split()等函數的功能
$a = new ArrayIterator(array('test1', 'test2', 'test3'));
$i = new RegexIterator($a, '/^(test)(\d+)/', RegexIterator::REPLACE);
$i->replacement = '$2:$1';
print_r(iterator_to_array($i));
/**output
Array
(
[0] => 1:test
[1] => 2:test
[2] => 3:test
)
**/
```
## IteratorIterator
一種通用類型的迭代器,所有實現了Traversable接口的類都可以被它迭代訪問。
## CachingIterator
用來執行提前讀取一個元素的迭代操作,例如可以用于確定當前元素是否為最后一個元素。
```
$array = array ('koala' , 'kangaroo' , 'wombat' , 'wallaby' , 'emu' , 'kiwi' , 'kookaburra' , 'platypus');
$object = new CachingIterator(new ArrayIterator($array));
foreach ($object as $value) {
echo $value;
if ($object->hasNext()) {
echo ','; //如果有下一項的話才輸出 突出不了該迭代器的作用啊,其他迭代器也可以搞定的
}
}
/**output
* koala,kangaroo,wombat,wallaby,emu,kiwi,kookaburra,platypus
**/
```
## SeekableIterator
用于創建非順序訪問的迭代器,允許跳轉到迭代器中的任何一點上。
```
$array = array("apple", "banana", "cherry", "damson", "elderberry");
$iterator = new ArrayIterator($array);
$iterator->seek(3); //起始0從第3個開始取;
echo $iterator->current().'<br />';
/**output
damson
**/
```
## NoRewindIterator
用于不能多次迭代的集合,適用于在迭代過程中執行一次性操作。
```
$fruit = array('apple', 'banana', 'cranberry');
$arr = new ArrayObject($fruit);
$it = new NoRewindIterator($arr->getIterator());
echo "Fruit A:\n";
foreach ($it as $item) {
echo $item . "\n";
}
echo "Fruit B:\n";
// ↓↓ 由于NoRewindIterator沒有rewind方法,所以foreach就不能用rewind重置游標,這個時候$it已經到最后了,所以為空;
foreach ($it as $item) {
echo $item . "\n";
}
/**output
Fruit A:
apple
banana
cranberry
Fruit B:
**/
```
## EmptyIterator
一種占位符形式的迭代器,不執行任何操作。當要實現某個抽象類的方法并且這個方法需要返回一個迭代器時,可以使用這種迭代器。
## InfiniteIterator
用于持續地訪問數據,當迭代到最后一個元素時,會再次從第一個元素開始迭代訪問。
```
$arrayit = new ArrayIterator(array('cat', 'dog'));
$infinite = new InfiniteIterator($arrayit);
//必須限制否則就是死循環
$limit = new LimitIterator($infinite, 0, 7);
foreach ($limit as $value) {
echo "$value\n";
}
```
## RecursiveArrayIterator
創建一個用于遞歸形式數組結構的迭代器,類似于多維數組.它為許多更復雜的迭代器提供了所需的操作,如RecursiveTreeIterator和RecursiveIteratorIterator迭代器。
```
$fruits = array("a" => "lemon", "b" => "orange", array("a" => "apple", "p" => "pear"));
$iterator = new RecursiveArrayIterator($fruits);
while ($iterator->valid()) {
//檢查是否含有子節點
if ($iterator->hasChildren()) {
//輸出所有字節點
foreach ($iterator->getChildren() as $key => $value) {
echo $key . ' : ' . $value . "\n";
}
} else {
echo "No children.\n";
}
$iterator->next();
}
/**output
No children.
No children.
a : apple
p : pear
**/
```
## RecursiveIteratorIterator
將一個樹形結構的迭代器展開為一維結構。
```
$fruits = array("a" => "lemon", "b" => "orange", array("a" => "apple", "p" => "pear",'c' => ['a','b']));
$arrayiter = new RecursiveArrayIterator($fruits);
$iteriter = new RecursiveIteratorIterator($arrayiter);
foreach ($iteriter as $key => $value) {
$d = $iteriter->getDepth();
echo "depth=$d k=$key v=$value\n";
}
/**output
depth=0 k=a v=lemon
depth=0 k=b v=orange
depth=1 k=a v=apple
depth=1 k=p v=pear
depth=2 k=0 v=a
depth=2 k=1 v=b
**/
```
## RecursiveTreeIterator
以可視在方式顯示一個樹形結構。
```
$hey = array("a" => "lemon", "b" => "orange", array("a" => "apple", "p" => "pear"));
$awesome = new RecursiveTreeIterator(
new RecursiveArrayIterator($hey),
null, null, RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($awesome as $line)
echo $line . PHP_EOL;
/**output
|-lemon
|-orange
|-apple
\-pear
**/
```
## ParentIterator
是一個擴展的FilterIterator迭代器,它可以過濾掉來自于RecursiveIterator迭代器的非父元素,只找出子節點的鍵值。通俗來說,就是去枝留葉。
```php
$hey = array ("a" => "lemon" , "b" => "orange" , array ("a" => "apple" , "p" => "pear"));
$arrayIterator = new RecursiveArrayIterator($hey);
$it = new ParentIterator($arrayIterator);
print_r(iterator_to_array($it));
/**output
* Array
* (
* [0] => Array
* (
* [a] => apple
* [p] => pear
* )
* )
**/
```
## RecursiveFilterIterator
是FilterIterator迭代器的遞歸形式,也要求實現抽象的accept()方法,但在這個方法中應該使用$this->getInnerIterator()方法訪問當前正在迭代的迭代器。
```
class TestsOnlyFilter extends RecursiveFilterIterator{
public function accept(){
// 找出含有“葉”的元素
return $this->hasChildren() || (mb_strpos($this->current() , "葉") !== false);
}
}
$array = array ("葉1" , array ("力2" , "葉3" , "葉4") , "葉5");
$iterator = new RecursiveArrayIterator($array);
$filter = new TestsOnlyFilter($iterator);
$filter = new RecursiveIteratorIterator($filter);
print_r(iterator_to_array($filter));
/**output
* Array
* (
* [0] => 葉1
* [1] => 葉3 //只會找出含葉的元素,不會把元素成員全部顯示出來
* [2] => 葉5
* )
**/
```
## RecursiveRegexIterator
是RegexIterator迭代器的遞歸形式,只接受RecursiveIterator迭代器作為迭代對象。
```php
$rArrayIterator = new RecursiveArrayIterator(array ('葉1' , array ('tet3' , '葉4' , '葉5')));
$rRegexIterator = new RecursiveRegexIterator(
$rArrayIterator , '/^葉/' , RecursiveRegexIterator::ALL_MATCHES
);
foreach ($rRegexIterator as $key1 => $value1) {
if ($rRegexIterator->hasChildren()) {
// print all children
echo "Children: ";
foreach ($rRegexIterator->getChildren() as $key => $value) {
echo $value . " ";
}
echo "\n";
} else {
echo "No children\n";
}
}
/**output
* No children
* Children: 葉4 葉5
**/
```
## RecursiveCachingIterator
在RecursiveIterator迭代器上執行提前讀取一個元素的遞歸操作。
## CallbackFilterIterator(PHP5.4)
同時執行過濾和回調操作,在找到一個匹配的元素之后會調用回調函數。
```php
$hey = array ("李1" , "葉2" , "葉3" , "葉4" , "葉5" , "葉6" ,);
$arrayIterator = new RecursiveArrayIterator($hey);
$isYe = function($current){
return mb_strpos($current , '葉') !== false;
};
$rs = new CallbackFilterIterator($arrayIterator , $isYe);
print_r(iterator_to_array($rs));
/**output
* Array
* (
* [0] => 葉2
* [1] => 葉3
* [2] => 葉4
* [3] => 葉5
* [4] => 葉6
* )
**/
```
## RecursiveCallbackFilterIterator(PHP5.4)
在RecursiveIterator迭代器上進行遞歸操作,同時執行過濾和回調操作,在找到一個匹配的元素之后會調用回調函數。
```php
function doesntStartWithLetterT($current){
$rs = $current->getFileName();
return $rs[0] !== 'T';
}
$rdi = new RecursiveDirectoryIterator(__DIR__);
$files = new RecursiveCallbackFilterIterator($rdi , 'doesntStartWithLetterT');
foreach (new RecursiveIteratorIterator($files) as $file) {
echo $file->getPathname() . PHP_EOL;
}
```
## DirectoryIterator
目錄文件遍歷器,提供了查詢當前文件的所有信息的方法(是否可讀可寫,所屬,權限等等),具體參考 http://cn2.php.net/manual/zh/class.directoryiterator.php
```php
$it = new DirectoryIterator("../");
foreach ($it as $file) {
//用isDot ()方法分別過濾掉“.”和“..”目錄
if (!$it->isDot()) {
echo $file . "\n";
}
}
```
## RecursiveDirectoryIterator
遞歸目錄文件遍歷器,可實現列出所有目錄層次結構,而不是只操作一個目錄。具體看:http://cn2.php.net/manual/zh/class.recursivedirectoryiterator.php
```php
//列出指定目錄中所有文件
$path = realpath('../');
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path) , RecursiveIteratorIterator::SELF_FIRST);
foreach ($objects as $name => $object) {
echo "$name\n";
}
```
## FilesystemIterator
是DirectoryIterator的遍歷器
```php
$it = new FilesystemIterator('../');
foreach ($it as $fileinfo) {
echo $fileinfo->getFilename() . "\n";
}
```
## GlobIterator
帶匹配模式的文件遍歷器
```php
$iterator = new GlobIterator('*.php');
if (!$iterator->count()) {
echo '無php文件';
} else {
$n = 0;
printf("總計 %d 個php文件\r\n" , $iterator->count());
foreach ($iterator as $item) {
printf("[%d] %s\r\n" , ++ $n , $iterator->key());
}
}
```
## SimpleXMLIterator
XMl文檔訪問迭代器,可實現訪問xml中所有節點
```php
$xml = <<<XML
<books>
<book>
<title>PHP Basics</title>
<author>Jim Smith</author>
</book>
<book>XML basics</book>
</books>
XML;
// SimpleXML轉換為數組
function sxiToArray($sxi){
$a = array ();
for ($sxi->rewind();$sxi->valid();$sxi->next()) {
if (!array_key_exists($sxi->key() , $a)) {
$a[$sxi->key()] = array ();
}
if ($sxi->hasChildren()) {
$a[$sxi->key()][] = sxiToArray($sxi->current());
} else {
$a[$sxi->key()][] = strval($sxi->current());
}
}
return $a;
}
$xmlIterator = new SimpleXMLIterator($xml);
$rs = sxiToArray($xmlIterator);
print_r($rs);
/**output
* Array
* (
* [book] => Array
* (
* [0] => Array
* (
* [title] => Array
* (
* [0] => PHP Basics
* )
* [author] => Array
* (
* [0] => Jim Smith
* )
* )
* [1] => XML basics
* )
* )
**/
```
## 參考鏈接:
http://www.ruanyifeng.com/blog/2008/07/php_spl_notes.html
http://www.cnblogs.com/ScriptZhang/archive/2010/05/25/1743875.html
- 現代化PHP特性
- php7常用特性整理
- 反射機制Reflection
- 依賴注入與服務容器
- 抽象類與接口
- 類多繼承的替代方案Traits
- 類的延遲綁定(后期綁定)
- 生成器語法
- 匿名函數和閉包
- 匿名類
- 理解php的output buffer
- 斷言ASSERT
- 魔術方法小結
- Zend Opcache字節碼緩存
- 內置的http服務器
- SPL標準庫
- 【SPL標準庫專題(1)】SPL簡介
- 【SPL標準庫專題(2)】Iterator
- 【SPL標準庫專題(3)】Classes
- 【SPL標準庫專題(4)】Exceptions
- 【SPL標準庫專題(5)】Datastructures:SplDoublyLinkedList
- 【SPL標準庫專題(6)】Datastructures:SplStack & SplQueue
- 【SPL標準庫專題(7)】Datastructures:SplPriorityQueue
- 【SPL標準庫專題(8)】Datastructures:SplHeap & SplMaxHeap & SplMinHeap
- 【SPL標準庫專題(9)】Datastructures:SplFixedArray
- 【SPL標準庫專題(10)】Datastructures:SplObjectStorage
- PHPcomposer使用手札[ing]
- PHP中的多態
- 通過命名空間實現自動加載的框架雛形
- 日期與金額
- PHPstorm使用攻略
- 筆記本