在上一篇文章中我们介绍了 php 的聚合迭代器接口,并对一些常见迭代器进行了简要的描述,正是这些 php 内置的迭代器,得以让我们应用的开发更具有灵活性,大大的提高了程序开发的速递。这一章节中我们将对其中的一些内置的迭代器做一个进一步的介绍。
OuterIterator 迭代器
OuterIterator 是一个迭代器接口它继承自 Iterator 迭代器,使用它你可以对多个对象进行迭代。除了来自 Iterator 迭代器的基本方法之外,OuterIterator 迭代器还额外提供了一个 getInnerIterator 方法用户获取当前迭代的对象,在实际的使用场景中我们往往不直接使用它二十使用它的实现 IteratorIterator 迭代器。它的使用场景为你需要对你的迭代对象进行额外的操作时。
<?php
class AnOuterIterator implements OuterIterator
{
protected $iterators = [];
protected $index = 0;
public function __construct(Array $iterators)
{
$this->iterators = $iterators;
}
public function getInnerIterator()
{
return $this->iterators[$this->index];
}
public function current()
{
return $this->getInnerIterator()->current();
}
public function next()
{
$this->getInnerIterator()->next();
if (!$this->getInnerIterator()->valid()) {
if ($this->index iterators)) {
$this->index++;
} else {
$this->getInnerIterator()->rewind();
}
}
}
public function valid()
{
return $this->index iterators);
}
public function rewind()
{
$this->index = 0;
$this->getInnerIterator()->rewind();
}
public function key()
{
return $this->getInnerIterator()->key();
}
}
$arrayIterator1 = new ArrayIterator([1, 2, 3, 4]);
$arrayIterator2 = new ArrayIterator([5, 6, 7, 8]);
$arrayIterator3 = new ArrayIterator([9, 10, 11, 12]);
$iterator = new AnOuterIterator([$arrayIterator1, $arrayIterator2, $arrayIterator3]);
foreach ($iterator as $key => $item) {
var_dump($item);
}
IteratorIterator 迭代器
IteratorIterator 实际上是一个实现了 OuterIterator 迭代器的包装器。他接受一个实现了 Traversable 的包装器作为参数,你可以像使用普通的迭代器一样去使用它。
<?php
$arrayIterate = new ArrayIterator(['a','b','c','d']);
$iterate = new IteratorIterator($arrayIterate);
//获取传入的迭代器实例
var_dump($iterate->getInnerIterator());
//遍历迭代
for ($iterate->rewind();$iterate->valid();$iterate->next()){
var_dump($iterate->current());
}
AppendIterator 迭代器
使用 AppendIterator 迭代器你将能够让你很方便的对迭代器进行顺序的遍历。AppendIterate 是来自 IteratorIterator 的子类,除了继承自使用 IteratorIterator 的方法外,他还额外提供了三个方法,他们的作用如下:
方法 | 作用 |
---|---|
append | 向 AppendIterator 迭代器追加一个迭代器 |
getIteratorIndex | 获取当前迭代的外部迭代器的序号 |
getArrayIterator | 获取通过 append 添加的 ArrayIterator 迭代器 |
<?php
$array_a = new ArrayIterator(['a', 'b', 'c']);
$array_b = new ArrayIterator(['d', 'e', 'f']);
//正则迭代器,在后边的内容我们将对他进行详细的介绍。
$array_c = new RegexIterator($array_a,'/^[acef]/');
$iterator = new AppendIterator();
$iterator->append($array_a);
$iterator->append($array_b);
foreach ($array_c as $item){
var_dump($array_c->current());
}
$a = [];
var_dump($iterator->getArrayIterator());
for ($iterator->rewind();$iterator->valid();$iterator->next()){
$currentIndex = $iterator->getIteratorIndex();
if(in_array($currentIndex,$a)){
var_dump($iterator->getInnerIterator());
$a[] = $currentIndex;
}
}
ArrayIterator 迭代器
ArrayIterator 迭代器是对 ArrayObject 的补充它为他提供了在遍历数组和对象时删除和更新值与键的能力。ArrayIterator 实际上实现了 ArrayAccess、CountAble、SeekableIterator 和 Serializable 所以它也具有了这些接口的能力。除了这些之外他还提供了一些额外的能力:
方法 | 作用 |
---|---|
asort | 按值排序 |
getArrayCopy | 获取传入迭代器数组的拷贝 |
getFlags | 获取传入迭代器的 flag 标识 |
ksort | 按键排序 |
natcasesort | 不区分大小写的排序 |
natsort | 自然排序 |
setflags | 设置行为标识 |
uasort | 使用用户定义的函数对值进行排序 |
uksort | 使用用户定义的函数对键进行排序 |
<?php
$iterator = new ArrayIterator(["111", '22', "111000", "123", "444", "55"]);
$iterator->asort();
$iterator->ksort();
var_dump($iterator->getFlags());
$iterator->setFlags(1);
var_dump($iterator->getFlags());
$iterator->natcasesort();
$iterator->natsort();
var_dump($iterator->offsetExists(6));
$iterator->uasort('u_asort');
$iterator->uasort('u_ksort');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->current());
}
function u_asort($a, $b)
{
return $a > $b;
}
function u_ksort($a, $b)
{
return $a rewind(); $iterator->hasNext(); $iterator->next()) {
var_dump($iterator->current());
}
echo PHP_EOL;
foreach ($iterator as $item) {
if ($iterator->hasNext()) {
var_dump($iterator->current());
}
}
var_dump($iterator->getCache());
FilterIterator 迭代器
FilterIterator 迭代器为你提供了对迭代对象进行过滤的能力,它继承自 IteratorIterator 并实现了 OuterIterator 接口,他还额外提供了一个 accept 方法,用来实现对当前迭代对象的过滤。
<?php
class AnFilterIterator extends FilterIterator
{
public function accept()
{
if (parent::current() > 3) {
return true;
}
return false;
}
}
$arrayIterator = new ArrayIterator([1, 2, 3, 4, 5, 6, 7]);
$iterator = new AnFilterIterator($arrayIterator);
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->current());
}
CallbackFilterIterator 迭代器
CallbackFilterIterator 迭代器继承自 FilterIterator 并实现了 OuterIterator 接口。与 FilterIterator 接口不同的是他的构造函数还接收一个额外的回调函数,用于处理对迭代的过滤。需要注意的是一旦你定义了 accept 方法用户自定义的 callback 方法将不会被调用。
<?php
class AnCallbackFilterIterator extends CallbackFilterIterator
{
public function accept()
{
echo 'accept is called' . PHP_EOL;
return $this->current() >= 3;
}
}
function callback($value, $key, $iterator)
{
echo "callback is called" . PHP_EOL;
return $value >= 5;
}
$arrayIterator = new ArrayIterator([99, 2, 3, 4, 5, 6, 7]);
$iterator = new AnCallbackFilterIterator($arrayIterator, 'callback');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->current());
}
SeekableIterator 迭代器
SeekableIterator 是 Iterator 接口的实现接口,除了 Iterator 接口的原生能力外他还为你提供了通过键值查找迭代数值的能力。此外在查找的迭代数值不存在时你需要抛出一个 OutOfBoundsException 异常。
<?php
class AnSeekableIterator implements SeekableIterator
{
private $array = [];
private $position = 0;
public function __construct(array $array)
{
$this->array = $array;
}
public function seek($position)
{
if (!isset($this->array[$this->position])) {
throw new OutOfBoundsException("invalid seek position ($position)");
}
echo 'seek is called' . PHP_EOL;
$this->position = $position;
}
public function current()
{
if (isset($this->array[$this->position])) {
return $this->array[$this->position];
}
throw new OutOfBoundsException("invalid current position $this->position");
}
public function next()
{
$this->position++;
}
public function key()
{
return $this->position;
}
public function valid()
{
return isset($this->array[$this->position]);
}
public function rewind()
{
$this->position = 0;
}
}
try {
$iterator = new AnSeekableIterator(['name', 'seven', 'sex', 'nan', 'age', '18']);
$iterator->seek(1);
var_dump($iterator->current());
$iterator->seek(100);
var_dump($iterator->current());
} catch (Exception $e) {
var_dump($e->getMessage());
}
DirectoryIterator 迭代器
DirectoryIterator 迭代器继承自 SplFileInfo 并实现了 SeekableIterator 接口,通过它提供的一系列接口你可以很方便的对目录进行遍历。 方法列表:
方 法 | 描述 |
---|---|
DirectoryIterator::getSize | 获取文件的大小 |
DirectoryIterator::getAtime | 获取当前迭代项的上一次访问时间 |
DirectoryIterator::getBasename | 获取当前迭代项的基本名称 |
DirectoryIterator::getCtime | 获取当前迭代项 inode 的上一次更改时间 |
DirectoryIterator::getExtension | 获取当前迭代项的扩展名 |
DirectoryIterator::getFilename | 获取当前迭代项的文件名 |
DirectoryIterator::getGroup | 获取当前迭代项所属组的 id |
DirectoryIterator::getInode | 获取当前迭代项的 inode 信息 |
DirectoryIterator::getMTime | 获取当前迭代项的上一次修改时间 |
DirectoryIterator::getOwner | 获取当前迭代项所属用户的 id |
DirectoryIterator::getPath | 获取当前迭代项不带文件名的路径 |
DirectoryIterator::getPathname | 获取当前迭代项带文件名的路径 |
DirectoryIterator::getPerms | 获取当前迭代项的权限信息(int) |
DirectoryIterator::getSize | 获取当前迭代项的大小信息 |
DirectoryIterator::getType | 推断当前迭代项的类型 |
DirectoryIterator::isDot | 当前迭代项是不是.或..,是返回 true 否则返回 false |
DirectoryIterator::isDir | 当前迭代项是不是文件夹,是返回 true 否则返回 false |
DirectoryIterator::isExecutable | 当前迭代项是不是可执行 |
DirectoryIterator::isFile | 获取当前迭代项是不是一个文件 |
DirectoryIterator::isLink | 获取当前项是不是一个符号链接 |
DirectoryIterator::isReadable | 获取当前项是不是可读 |
DirectoryIterator::isWritable | 获取当前项是不是可写 |
$iterator = new DirectoryIterator('../iterator');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
if ($iterator->isFile() && $iterator->isReadable()) {
var_dump($iterator->getSize());
}
}
EmptyIterator 迭代器
EmptyIterator 迭代器的使用场景为某些异常情况下你需要返回一个迭代对象时使用,如在 getIterator 方法中你必须获取一个迭代器类型。
<?php
class AnEmptyIterator implements IteratorAggregate
{
private $url;
public function __construct($url)
{
$this->url = $url;
}
public function getIterator()
{
$content = file_get_contents($this->url);
try {
return @new SimpleXMLIterator($content);
} catch (Exception $e) {
// Case $content is not valid XML, but you don't care
return new EmptyIterator();
}
}
}
FilesystemIterator 迭代器
FilesystemIterator 迭代器 DirectoryIterator 迭代器并实现了 SeekableIterator 接口。不同于 DirectoryIterator 迭代器,FilesystemIterator 迭代器每次迭代都是一个新的 SplFileInfo 对象,而且默认情况下返回的都是完整的路径名,并且你也可以通过设置 flag 参数来更改返回的信息。也就是说 DirectoryIterator 的每一次迭代迭代对象的值都会改变但是 FilesystemIterator 迭代器并不会。 FilesystemIterator 迭代器在迭代的过程中会忽略.和..
$iterator = new FilesystemIterator('./');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->getFilename() . "--" . $iterator->getSize());
}
GlobIterator 迭代器
GlobIterator 迭代器继承自 FilesystemIterator 并实现了 SeekableIterator 和 Countable 接口是一个带匹配模式的迭代器,使用它你可灵活的控制你的迭代需求。
<?php
$iterator = new GlobIterator('./*.txt');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->getFilename());
}
LimitIterator 迭代器
LimitIterator 迭代器对一个迭代器进行限定的迭代。
<?php
$arrayIterator = new ArrayIterator([1, 2, 3, 4, 5]);
foreach (new LimitIterator($arrayIterator, 1, 3) as $item) {
var_dump($item);
}
InfiniteIterator 迭代器
InfiniteIterator 迭代器是一个无限循环的迭代器,当迭代到最后一个节点时内部会自动的实现将迭代重置到最开始的位置。
<?php
$arrayIterator = new ArrayIterator([1, 2, 3, 4, 5, 6, 7, 8, 9]);
$iterator = new InfiniteIterator($arrayIterator);
foreach (new LimitIterator($iterator, 0, 18) as $item) {//迭代18次后停止
var_dump($item);
}
MultipleIterator 迭代器
MultipleIterator 是一个迭代连接器,使用它你可以对几个迭代器进行连接迭代。
<?php
$name = ["zhangsan", "lisi", "wangwu"];
$sex = ["男", "女", "男"];
$age = [17, 18, 19];
$nameIterator = new ArrayIterator($name);
$ageIterator = new ArrayIterator($age);
$sexIterator = new ArrayIterator($sex);
$iterator = new MultipleIterator();
$iterator->attachIterator($nameIterator, "name");
$iterator->attachIterator($ageIterator, 'age');
$iterator->attachIterator($sexIterator, 'sex');
for ($iterator->rewind(); $iterator->valid(); $iterator->next()) {
var_dump($iterator->current());
}
array(3) {
[0]=>
string(8) "zhangsan"
[1]=>
int(17)
[2]=>
string(3) "男"
}
array(3) {
[0]=>
string(4) "lisi"
[1]=>
int(18)
[2]=>
string(3) "女"
}
array(3) {
[0]=>
string(6) "wangwu"
[1]=>
int(19)
[2]=>
string(3) "男"
}
NoRewindIterator 迭代器
NoRewindIterator 迭代器不允许 rewind 操作,这意味着你将只能对迭代对象进行一次迭代。
<?php
$arrayIterator = new ArrayIterator([1, 2, 3, 4, 5, 6, 7]);
$iterator = new NoRewindIterator($arrayIterator);
foreach ($iterator as $item) {
var_dump($item);
}
foreach ($iterator as $item) {
var_dump($item);
}
RegexIterator 迭代器
RegexIterator 迭代器是 FilterIterator 的子类,它为你的数据迭代提供了使用正则过滤数据的能力。除了来自父类的方法外他还额外提供了一些有用的方法:
方法 | 解释 |
---|---|
getFlags | 获取当前的 flag 参数 |
setFlags | 动态的设置 flag 参数 |
getRegex | 获取你传入的正则表达式 |
getPregFlags | 获取当前的 PregFlags 参数 |
setPregFlags | 动态的设置 setPregFlags 参数 |
getMode | 获取当前的匹配模式 |
setMode | 动态的设置匹配模式 |
accept | 在这里对当前迭代的元素进行进一步的过滤 |
<?php
$arrayIterator = new ArrayIterator(["a", "b", "c", "d"]);
$iterator = new RegexIterator($arrayIterator, '/^[abc]/');
foreach ($iterator as $item) {
var_dump($item);
}