当前的PHP foreach项是迭代程序中的最后一个项吗


Is the current PHP foreach item the last one in the Iterator?

在Php中迭代迭代器时,例如symfonys-finder(composer require symfony/finder):

$files = 'Symfony'Component'Finder'Finder::create()
            ->in('searchdir')
            ->directories()
            ->depth(0)
            ->sortByType();
foreach ($files as $file) {
    //is $file the last element?
}

检查$file是否是$files迭代器中的最后一项的最佳方法是什么?

如果你在迭代某个东西,并且你真的很关心项目的索引,你可以使用经典的结构:

for($i=0; $i<count($iterator);$i++) {
    if($i==count($iterator)-1) {
        // You reached the last item
    }
}

或者也可以像这样使用$key=>$value:

foreach($iterator as $iteratorKey=>$iteratorValue) {
    if($iteratorKey==count($iterator)-1) {
        // You reached the last item
    }
}

由于我收到的两个问题答案都是明显错误的,让我用我发现的答案来回答:

方法1

你可以得到最后一个这样的密钥:

$last = null;
foreach($files as $key => $value) {
   $last = $key;
}

然后比较迭代中的密钥:

foreach ($iterator as $key => $value) {
    if ($key === $last) {
        ....
    }
}

方法2

如果迭代器实现了seek方法并且是Countable(或者有一个count-方法),那么您也可以获得最后一个密钥,如下所示:

$iterator->seek(count($iterator) - 1); 
$last = $iterator->key();

起初,这似乎是一个更干净的解决方案,但根据我对symfonys finder类的测试(5000个文件,对两种方法都测试了100次),这大约是使用foreach函数的3倍慢。专家能解释一下原因吗?

方法3

我现在使用的解决方案是这样的,因为它尽可能减少开销(如果迭代器不是Countable(大多数都是),请使用迭代器计数而不是count):

$index = 0;
$length = count($iterator);
foreach ($iterator as $item) {
    $index++;
    if ($index == $length) {
        // last item!
    }
}

您也可以这样做:

$cachingIterator = new 'CachingIterator($iterator, 'CachingIterator::FULL_CACHE);
while ($iterator->valid()) {
    $cachingIterator->next();
}
$lastKey = $cachingIterator->key();
$lastCurrentValue = $cachingIterator->current();

这在loopwp/collection的Last操作中实现。