我需要递归遍历所有数组元素(即,对于遇到的每个数组元素本身就是一个数组,我需要迭代该数组)并对每个字符串(叶子)值执行trim()
。
要使用与下面链接中提到的示例非常相似的示例,这就是我需要的:
<?php
// How to accomplish identical functionality using PHP iterators?
$sweet = array('a' => ' apple ', 'b' => ' banana ');
$fruits = array('sweet' => $sweet, 'sour' => ' lemon ');
function my_trim(&$item, $key)
{
// Trim the whitespace from the values
$item = trim($item);
}
array_walk_recursive($fruits, 'my_trim');
?>
函数array_walk_recursive提供了我所需的功能。
但是,我想更好地理解PHP迭代器,并且通过使用迭代器实现与array_walk_recursive()
函数相同的功能,我当前的任务似乎是一个很好的机会。
当我转到PHP documentation for iterators时,我看到了各种迭代器,但没有对它们语义的整体描述。特别是,RecursiveArrayIterator似乎是明显的选择,如果不是RecursiveIteratorIterator类和this StackOverflow answer类似的问题(它给出了代码但不解释代码)令我满意的是,我只是试图使用前迭代器(RecursiveArrayIterator
),我甚至可能都没有发布过这个问题。
但是,我尝试实际查看两个相关迭代器类的文档 - RecursiveArrayIterator
和RecursiveIteratorIterator
- 以便了解上述链接中的代码并且对它的使用感到满意(或没有) - 我在Google搜索中的任何地方都没有找到这些迭代器语义的文档(特别是,我在官方PHP文档中没有看到这些迭代器的介绍性文档,如上所述)。
因此,我想知道使用PHP迭代器实现array_walk_recursive()
函数的相同功能的正确方法是什么。 (据推测,如果上面的SO链接中的代码是正确的,它将与链接代码完全(或类似) - 但我不仅仅是代码片段,还有(简要)解释。)
答案 0 :(得分:1)
我不知道使用RecursiveIteratorIterator
修改原始数组的简单方法,而是使用array_walk_recursive
,因为您的示例是更好的选择。
如果您只想访问多维数组的叶子而不修改原始数组,可以使用LEAVES_ONLY
选项。
$sweet = array('a' => ' apple ', 'b' => ' banana ');
$fruits = array('sweet' => $sweet, 'sour' => ' lemon ');
foreach (new RecursiveIteratorIterator(
new RecursiveArrayIterator($fruits),
RecursiveIteratorIterator::LEAVES_ONLY
) as $key => $value) {
print trim($value);
}
请注意,在上面的foreach
中引用$ value即as $key => &$value
是非法的,在这种情况下php会产生以下错误
PHP Fatal error: An iterator cannot be used with foreach by reference
RecursiveIteratorIterator
以递归方式迭代任何实现Traversable
(和扩展名Iterator
)接口的递归对象。对于嵌套数组,您需要一个RecursiveArrayIterator
迭代器对象
但您也可以RecursiveDirectoryIterator
遍历文件系统。
您遍历对象的路径可以由RecursiveIteratorIterator
的第二个参数指定:
RecursiveIteratorIterator::LEAVES_ONLY - The default. Lists only leaves in iteration.
RecursiveIteratorIterator::SELF_FIRST - Lists leaves and parents in iteration with parents coming first.
RecursiveIteratorIterator::CHILD_FIRST - Lists leaves and parents in iteration with leaves coming first.
答案 1 :(得分:1)
Iterator并不意味着修改它的内部元素。 Iterator用于在foreach循环中逐个访问元素集合。
当然,您可以以返回字符串的修改版本的方式覆盖Iterator的current()
函数。但是,您仍然需要自己迭代所有元素来修改它们。
我试着通过例子解释:
$sweet = array('a' => ' apple ', 'b' => ' banana ');
$fruits = array('sweet' => $sweet, 'sour' => ' lemon ');
创建自定义RecursiveIteratorIterator
:
class CallbackRecursiveIteratorIterator extends
RecursiveIteratorIterator
{
public function __construct(RecursiveIterator $it, $callback) {
$this->callback = $callback;
parent::__construct($it);
}
public function current() {
return $this->callback->__invoke(parent::current());
}
}
创建该迭代器的实例:
$i = new CallbackRecursiveIteratorIterator (
new RecursiveArrayIterator(
$fruits
),
// pass callback here
function($element) {
return trim($element . " test");
}
);
// Iterate over modified values
foreach($i as $key => $el) {
var_dump($el);
}
请注意,原始数组仍未更改:
var_dump($fruits);