PHP Conference Japan 2024

RecursiveIteratorIterator 类

(PHP 5、PHP 7、PHP 8)

简介

可用于迭代递归迭代器。

类摘要

class RecursiveIteratorIterator implements OuterIterator {
/* 常量 */
public const int LEAVES_ONLY;
public const int SELF_FIRST;
public const int CHILD_FIRST;
public const int CATCH_GET_CHILD;
/* 方法 */
public __construct(Traversable $iterator, int $mode = RecursiveIteratorIterator::LEAVES_ONLY, int $flags = 0)
public current(): mixed
public endChildren(): void
public endIteration(): void
public getDepth(): int
public key(): mixed
public next(): void
public nextElement(): void
public rewind(): void
public setMaxDepth(int $maxDepth = -1): void
public valid(): bool
}

目录

添加注释

用户贡献的注释 7 条注释

21
匿名
8 年前
RecusiveIteratorIterator 与 RecursiveArrayIterator 结合使用的一个非常有用的用例是替换多维数组中任何深度的数组值。

通常,`array_walk_recursive` 用于替换数组深层的值,但不幸的是,这只有在存在标准键值对时才有效 - 换句话说,`array_walk_recursive` **只访问叶子节点,而不是数组**。

所以为了解决这个问题,可以使用迭代器,方法如下:

<?php
$array
= [
'test' => 'value',
'level_one' => [
'level_two' => [
'level_three' => [
'replace_this_array' => [
'special_key' => 'replacement_value',
'key_one' => 'testing',
'key_two' => 'value',
'four' => 'another value'
]
],
'ordinary_key' => 'value'
]
]
];

$arrayIterator = new \RecursiveArrayIterator($array);
$recursiveIterator = new \RecursiveIteratorIterator($arrayIterator, \RecursiveIteratorIterator::SELF_FIRST);

foreach (
$recursiveIterator as $key => $value) {
if (
is_array($value) && array_key_exists('special_key', $value)) {
// 在这里,我们将所有键替换为来自'special_key'的相同值
$replaced = array_fill(0, count($value), $value['special_key']);
$value = array_combine(array_keys($value), $replaced);
// 设置一个新键
$value['new_key'] = 'new value';

// 获取当前深度并遍历回树的顶部,保存修改
$currentDepth = $recursiveIterator->getDepth();
for (
$subDepth = $currentDepth; $subDepth >= 0; $subDepth--) {
// 获取当前级别的迭代器
$subIterator = $recursiveIterator->getSubIterator($subDepth);
// 如果我们在想要更改的级别上,使用替换($value),否则将键设置为父迭代器的值
$subIterator->offsetSet($subIterator->key(), ($subDepth === $currentDepth ? $value : $recursiveIterator->getSubIterator(($subDepth+1))->getArrayCopy()));
}
}
}
return
$recursiveIterator->getArrayCopy();
// 返回值:
$array = [
'test' => 'value',
'level_one' => [
'level_two' => [
'level_three' => [
'replace_this_array' => [
'special_key' => 'replacement_value',
'key_one' => 'replacement_value',
'key_two' => 'replacement_value',
'four' => 'replacement_value',
'new_key' => 'new value'
]
],
'ordinary_key' => 'value'
]
]
];
?>

关键在于遍历回树的顶部以在该级别保存更改 - 仅仅调用 `$recursiveIterator->offsetSet();` 只会设置根数组上的键。
13
Michiel Brandenburg
15 年前
您可以使用它快速查找特定目录中(递归)的所有文件。这比自己维护一个栈要好。
<?php
$directory
= "/tmp/";
$fileSPLObjects = new RecursiveIteratorIterator(
new
RecursiveDirectoryIterator($directory),
RecursiveIteratorIterator::CHILD_FIRST
);
try {
foreach(
$fileSPLObjects as $fullFileName => $fileSPLObject ) {
print
$fullFileName . " " . $fileSPLObject->getFilename() . "\n";
}
}
catch (
UnexpectedValueException $e) {
printf("Directory [%s] contained a directory we can not recurse into", $directory);
}
?>
注意:如果在您正在搜索的目录中包含一个您无权读取的目录,则会抛出 `UnexpectedValueException`(导致您得到一个空列表)。
注意:返回的对象是 `SPLFileObjects`。
10
Adil Baig @ AIdezigns
13 年前
关于 `\RecursiveIteratorIterator` 需要注意的一件非常重要的事情是,当与 `iterator_to_array` 函数一起使用时,它会返回一个扁平化的数组。例如:

<?php
$arr
= array('Zero', 'name'=>'Adil', 'address' => array( 'city'=>'Dubai', 'tel' => array('int' => 971, 'tel'=>12345487)), '' => 'nothing');

$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($arr));
var_dump(iterator_to_array($iterator,true));
?>

这段代码将返回:

array(6) {
[0]=>
string(4) "Zero"
["name"]=>
string(4) "Adil"
["city"]=>
string(5) "Dubai"
["int"]=>
int(91)
["tel"]=>
int(12345487)
[""]=>
string(7) "nothing"
}

要获得未扁平化的正确数组,请使用 `getArrayCopy()` 方法,如下所示:

$iterator->getArrayCopy()

这将返回:

array(4) {
[0]=>
string(4) "Zero"
["name"]=>
string(4) "Adil"
["address"]=>
array(2) {
["city"]=>
string(5) "Dubai"
["tel"]=>
array(2) {
["int"]=>
int(91)
["tel"]=>
int(12345487)
}
}
[""]=>
string(7) "nothing"
}
10
aidan at php dot net
14 年前
此示例演示了如何将 `getDepth()` 方法与 `RecursiveArrayIterator` 一起使用。

<?php
$tree
= array();
$tree[1][2][3] = 'lemon';
$tree[1][4] = 'melon';
$tree[2][3] = 'orange';
$tree[2][5] = 'grape';
$tree[3] = 'pineapple';

print_r($tree);

$arrayiter = new RecursiveArrayIterator($tree);
$iteriter = new RecursiveIteratorIterator($arrayiter);

foreach (
$iteriter as $key => $value) {
$d = $iteriter->getDepth();
echo
"depth=$d k=$key v=$value\n";
}
?>

这将输出:

Array
(
[1] => Array
(
[2] => Array
(
[3] => lemon
)

[4] => melon
)

[2] => Array
(
[3] => orange
[5] => grape
)

[3] => pineapple
)

depth=2 k=3 v=lemon
depth=1 k=4 v=melon
depth=1 k=3 v=orange
depth=1 k=5 v=grape
depth=0 k=3 v=pineapple
7
gerry at king-foo dot be
10 年前
使用 `iterator_to_array()` 时要小心。因为它会将您的子迭代器扁平化,具有相同键的元素会相互覆盖。

例如:

<?php

$iterator
= new RecursiveIteratorIterator(
new
RecursiveArrayIterator([
[
'foo', 'bar'],
[
'baz', 'qux']
])
);

foreach (
$iterator as $element) {
echo
$element;
}

?>

这将按预期输出所有 4 个元素:

string(3) "foo"
string(3) "bar"
string(3) "baz"
string(3) "qux"

而执行:

<?php

var_dump
(iterator_to_array($iterator));

?>

将输出一个只包含最后两个元素的数组。

array(2) {
[0]=>
string(3) "baz"
[1]=>
string(3) "qux"
}
4
Tom
13 年前
此类在一个元素树上操作,该树通过将递归迭代器相互嵌套来构建。

因此,可以说它是一个迭代器迭代器。在遍历这些迭代器时,该类在向下遍历到叶子时将迭代器压入堆栈,并在返回时将其从堆栈中移除。
2
fengdingbo at gmail dot com
11 年前
如果您想遍历目录。
<?php
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator("./")) as $key=>$val)
{
echo
$key,"=>",$val,"\n";
}
?>
To Top