php - 如何在使用 RecursiveArrayIterator 时更改数组键和值?

标签 php iterator spl arrayiterator

我怀疑我在这里做了一些愚蠢的事情,但我对 SPL 的一个看似简单的问题感到困惑:

如何使用 RecursiveArrayIterator 修改数组的内容(本例中的值)/RecursiveIteratorIterator

使用以下测试代码,我可以使用 getInnerIterator() 更改循环内的值和 offsetSet() ,并在循环中转储修改后的数组。

但是当我离开循环并从迭代器中转储数组时,它又回到了原始值。发生了什么事?

$aNestedArray = array();
$aNestedArray[101] = range(100, 1000, 100);
$aNestedArray[201] = range(300, 25, -25);
$aNestedArray[301] = range(500, 0, -50);

$cArray = new ArrayObject($aNestedArray);
$cRecursiveIter = new RecursiveIteratorIterator(new RecursiveArrayIterator($cArray), RecursiveIteratorIterator::LEAVES_ONLY);

// Zero any array elements under 200  
while ($cRecursiveIter->valid())
{
    if ($cRecursiveIter->current() < 200)
    {
        $cInnerIter = $cRecursiveIter->getInnerIterator();
        // $cInnerIter is a RecursiveArrayIterator
        $cInnerIter->offsetSet($cInnerIter->key(), 0);
    }

    // This returns the modified array as expected, with elements progressively being zeroed
    print_r($cRecursiveIter->getArrayCopy());

    $cRecursiveIter->next();
}

$aNestedArray = $cRecursiveIter->getArrayCopy();

// But this returns the original array.  Eh??
print_r($aNestedArray);

最佳答案

似乎普通数组中的值是不可修改的,因为它们不能通过引用传递给 ArrayIterator 的构造函数(RecursiveArrayIterator 继承了它的 offset *() 方法,参见 SPL Reference )。所以对 offsetSet() 的所有调用都在数组的副本上工作。

我猜他们选择避免​​按引用调用是因为它在面向对象的环境中没有多大意义(即当传递 ArrayObject 的实例时,这应该是默认情况)。

一些更多的代码来说明这一点:

$a = array();

// Values inside of ArrayObject instances will be changed correctly, values
// inside of plain arrays won't
$a[] = array(new ArrayObject(range(100, 200, 100)),
             new ArrayObject(range(200, 100, -100)),
             range(100, 200, 100));
$a[] = new ArrayObject(range(225, 75, -75));

// The array has to be
//     - converted to an ArrayObject or
//     - returned via $it->getArrayCopy()
// in order for this field to get handled properly
$a[] = 199;

// These values won't be modified in any case
$a[] = range(100, 200, 50);

// Comment this line for testing
$a = new ArrayObject($a);

$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($a));

foreach ($it as $k => $v) {
    // getDepth() returns the current iterator nesting level
    echo $it->getDepth() . ': ' . $it->current();

    if ($v < 200) {
        echo "\ttrue";

        // This line is equal to:
        //     $it->getSubIterator($it->getDepth())->offsetSet($k, 0);
        $it->getInnerIterator()->offsetSet($k, 0);
    }

    echo ($it->current() == 0) ? "\tchanged" : '';
    echo "\n";
}

// In this context, there's no real point in using getArrayCopy() as it only
// copies the topmost nesting level. It should be more obvious to work with $a
// itself
print_r($a);
//print_r($it->getArrayCopy());

关于php - 如何在使用 RecursiveArrayIterator 时更改数组键和值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1228575/

相关文章:

c++ - 在打印 vector 内容时添加空格和新行

php - SplPriorityQueue::next() 正在删除项目

php - 哪个 PHP 接口(interface)允许使用数组表示法访问对象的属性?

javascript - 嵌入缩略图 Youtube 视频

php - 从特定单词到另一个单词的字符串,即使这些单词在一个字符串中不止一次

c++ - it = map.find (element) == map.end() have it->second 是否正常?

java - 为什么父线程没有在子线程之后执行?

php - 为什么这里使用clone关键字

php - 按多个 id 对 MySQL 查询进行排序

phpquery codeigniter 方法