Могу ли я заставить RecursiveDirectoryIterator пропускать нечитаемые каталоги?

foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator(".")) as $file) {
  echo "$file\n";
}

Есть ли какой-либо способ для этого кода не выбрасывать UnexpectedValueException "не удалось открыть dir: Permission denied" всякий раз, когда есть недопустимый подкаталог внутри каталога, который я пытаюсь перечислить?

UPDATE

Преобразование foreach() в while() и явно вызов Iterator::next(), завернутый в try() catch {}, не помогает. Этот код:

$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."));
while($iter->valid()) {
    $file = $iter->current();
    echo "$file\n";
    try {
        $iter->next();
    } catch(UnexpectedValueException $e) {
    }
};

является бесконечным циклом, если существует нечитаемый подкаталог.

Ответы

Ответ 1

По-видимому, вы можете передать параметр $flags в конструктор. Там только один флаг в документах, но он делает именно то, что вы хотите: catches exceptions during getChildren() calls and simply jumps to the next element.

Измените код создания класса на

new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator("."), 
    RecursiveIteratorIterator::LEAVES_ONLY,
    RecursiveIteratorIterator::CATCH_GET_CHILD);

и он должен работать

Ответ 2

Вы можете сделать что-то вроде этого:

class ReadableFilter extends RecursiveFilterIterator{
    public function accept(){
            return $this->current()->isReadable();
    }
}

$filteredIterator = new RecursiveIteratorIterator(new ReadableFilter(new RecursiveDirectoryIterator(".")));

foreach ($filteredIterator as $file){
    echo "$file\n";
}

Ответ 3

Возможно, позиция итератора будет действительна, даже если каталог не читается.

Вы можете проверить состояние записи в каталоге. Неверный непроверенный пример кода:

$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("."));
foreach ($iter as $dir) {
    if($dir->isReadable()){
        //do something
    }
}