Skip to content

在上一篇文章中我们介绍了一些内置的迭代器的基本使用,在这一篇文章中我们将继续对另外的一些迭代器进行学习,他们是 RecursiveIterator(递归迭代器)系列迭代器,他们主要在需要对迭代器进行递归迭代时使用。

RecursiveIterator 迭代器

RecursiveIterator 迭代器接口继承 Iterator 迭代器,它为你的迭代器提供了递归访问的能力。使用它你可以很方便的对于一些多层数据行迭代处理,除了继承于 Iterator 迭代器的基本功能外,他还提供了 hasChildren 和 getChildren 两个方法。其中 getChildRen 的返回值必须是一个 RecursiveIterator 迭代器对象。

php
<?php

class AnRecursiveIterator implements RecursiveIterator
{
    private $iterators;
    private $index = 0;

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

    public function current()
    {
        return $this->iterators[$this->index];
    }

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

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

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

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

    /**
     * 是否有子节点
     * @return bool
     */
    public function hasChildren()
    {
        return is_array($this->iterators[$this->index]);
    }

    /**
     * 获取子节点迭代对象
     * @return RecursiveIterator
     */
    public function getChildren(): RecursiveIterator
    {
        return new self($this->iterators[$this->index]);
    }
}

$iterator = new AnRecursiveIterator([1, 2, 3, 4, [5, 6, 7, [8, 9, 10, 11]]]);
function recursive(RecursiveIterator $iterator, $i = 0)
{
    foreach ($iterator as $key => $item) {
        echo str_repeat("\t", $i);
        if ($iterator->hasChildren()) {
            echo $key . ' has children' . PHP_EOL;
            recursive($iterator->getChildren(), $i + 1);
        } else {
            echo $key . '.....' . $item . PHP_EOL;
        }
    }
}

recursive($iterator);

RecursiveArrayIterator 迭代器

RecursiveArrayIterator 迭代器继承自 ArrayIterator 并实现了 RecursiveIterator 接口,所以它兼具了 ArrayIterator 迭代器和 RecursiveIterator 迭代器的功能。使用它你可以更加灵活的对数据进行遍历迭代。

php
<?php

$iterator = new RecursiveArrayIterator([1, 2, 3, 4, 5, 7, 'test' => [11, 22, 33, 44, 55, 66]], RecursiveArrayIterator::CHILD_ARRAYS_ONLY);

function arrayRecursive(RecursiveArrayIterator $iterator, int $i = 0)
{
    foreach ($iterator as $key => $item) {
        echo str_repeat("\t", $i);
        if ($iterator->hasChildren()) {
            echo $key . ' has children' . PHP_EOL;
            arrayRecursive($iterator->getChildren(), $i + 1);
        } else {
            echo $key . '.....' . $item . PHP_EOL;
        }
    }
}

arrayRecursive($iterator);

RecursiveCachingIterator 迭代器

RecursiveCachingIterator 迭代器是 CachingIterator 迭代器的子类并在此基础上实现了 Countable、ArrayAccess、OuterIterator、RecursiveIterator 接口。在 CachingIterator 迭代器基础上实现了递归迭代的能力。

php
<?php

$arrayIterator = new RecursiveArrayIterator([1, 2, 3, 4, 56, 7, 8, 'test' => [11, 22, 33, 44, 55]]);
$iterator = new RecursiveCachingIterator($arrayIterator, 256);

function recursiveCaching(RecursiveCachingIterator $iterator, $i = 0)
{
    foreach ($iterator as $item) {
        if ($iterator->hasChildren()) {
            echo $iterator->key() . ' has children ' . PHP_EOL;
            recursiveCaching($iterator->getChildren(), $i+1);
        } else {
            echo $iterator->key() . '.....' . $item . PHP_EOL;
        }
        if (!$iterator->hasNext()) {
            echo $iterator->key() . ' is the end element' . PHP_EOL;
        }
    }
}

recursiveCaching($iterator);
//var_dump($iterator->getCache());

RecursiveCallbackFilterIterator 迭代器

RecursiveCallbackFilterIterator 迭代器 CallbackFilterIterator 并在此基础上实现了 OuterIterator 和 RecursiveIterator 接口。

php
<?php
class AnRecursiveCallbackFilterIterator extends RecursiveCallbackFilterIterator
{
    public function accept()
    {
        return $this->current() >= 3;
    }
}

function callback($value, $key, $iterator)
{
    return $value >= 5;
}

$arrayIterator = new RecursiveArrayIterator([99, 2, 3, 4, 5, 6, 7, 'test' => [11, 22, 33, 44, 55, 66, 77]]);
$iterator = new AnRecursiveCallbackFilterIterator($arrayIterator, 'callback');

function recursiveCallback(RecursiveCallbackFilterIterator $iterator, $i = 0)
{
    foreach ($iterator as $item) {
        echo str_repeat("\t", $i);
        if ($iterator->hasChildren()) {
            echo $iterator->key() . ' has children ' . PHP_EOL;
            recursiveCallback($iterator->getChildren(), $i+1);
        } else {
            echo $iterator->key() . '.....' . $item . PHP_EOL;
        }
    }
}

recursiveCallback($iterator);

RecursiveDirectoryIterator 迭代器

RecursiveDirectoryIterator 继承自 FilesystemIterator 并实现了 SeekableIterator 和 RecursiveIterator 接口,除了来自父类和实现接口的一些方法外他自身还提供了 getSubPath、getSubPathname 两个方法,他的迭代返回值为一个 splFileInfo 对象信息,这使得很容易的对目录进行迭代遍历。

php
<?php
$iterator = new RecursiveDirectoryIterator(__DIR__,RecursiveDirectoryIterator::SKIP_DOTS);

function recursiveDir(RecursiveDirectoryIterator $iterator, $i = 0)
{
    foreach ($iterator as $item) {
        if ($iterator->isDir()) {
            recursiveDir(new RecursiveDirectoryIterator($iterator->getPathname(),RecursiveDirectoryIterator::SKIP_DOTS), $i + 1);
        } else {
            var_dump($item);
        }
    }
}

recursiveDir($iterator);

RecursiveFilterIterator 迭代器

RecursiveFilterIterator 迭代器是 FilterIterator 的子类并实现了 OuterIterator 和 RecursiveIterator 接口,使用它你可以对迭代对象的输出进行迭代过滤。

php
<?
php class AnRecursiveFilterIterator extends RecursiveFilterIterator
{
    public function __construct(RecursiveIterator $iterator)
    {
        parent::__construct($iterator);
    }

    public function accept()
    {
        return $this->hasChildren() || strpos((string)$this->current(), '1') !== false;
    }
}

$arrayIterator = new RecursiveArrayIterator([1, 2, 3, 4, 5, 6, 7, 8, 9, new RecursiveArrayIterator([11, 22, 33, 44, 55, 66])]);
$iterator = new AnRecursiveFilterIterator($arrayIterator);
function RecursiveFilter(RecursiveFilterIterator $iterator, $i = 0)
{
    foreach ($iterator as $item) {
        echo str_repeat("\t", $i);
        if ($iterator->hasChildren()) {
            echo $iterator->key() . ' has children' . PHP_EOL;
            RecursiveFilter($iterator->getChildren(), $i + 1);
        } else {
            echo $iterator->current() . '.....' . $item . PHP_EOL;
        }
    }
}

RecursiveFilter($iterator);

RecursiveIteratorIterator 迭代器

RecursiveIteratorIterator 迭代器是 OuterIterator 迭代器的实现接口,使用它你可以对实现了 RecursiveIterator 的迭代器进行迭代。

php
<?php $arrayIterator = new RecursiveArrayIterator([1, 2, 3, 4, [1, 2, 3, 4, 5],
    new RecursiveArrayIterator([12222, 333333, new RecursiveArrayIterator([1111, 2222, 3333, 4444])])]);
$iterator = new RecursiveIteratorIterator($arrayIterator);

function RecursiveIterator(RecursiveIteratorIterator $iterator)
{
    foreach ($iterator as $item) {
        echo str_repeat("\t", $iterator->getDepth());
        echo $iterator->getDepth() . '....' . $item . PHP_EOL;
    }
}

RecursiveIterator($iterator);

RecursiveRegexIterator 迭代器

RecursiveRegexIterator 是 RegexIterator 迭代器的子类,并在此基础上实现了 RecursiveIterator 迭代器接口,使得你可以对迭代的数据应用正则过滤。

php
<?php
$arrayIterator = new RecursiveArrayIterator([12, 3, 'abc123', 'bac213', [1122, 2233, 3344, 4455]]);
$iterator = new RecursiveRegexIterator($arrayIterator, '/^[123]/');
function RecursiveRegex(RecursiveRegexIterator $iterator)
{
    foreach ($iterator as $item) {
        if ($iterator->hasChildren()) {
            RecursiveRegex($iterator->getChildren());
        } else {
            var_dump($item);
        }
    }
}

RecursiveRegex($iterator);

RecursiveTreeIterator 迭代器

RecursiveTreeIterator 迭代器是一个树形结构迭代器,使用它你可以很方便的遍历一个树形结构。

php
<?php
$arrayIterator = new RecursiveArrayIterator([1, 2, [3, 4, [5, 6, 7], 8], 9, 10]);
$iterator = new RecursiveTreeIterator($arrayIterator);

foreach ($iterator as $key => $value) {
    echo $value . PHP_EOL;
}