Поиск и сортировка файлов средствами PHP (SPL)

В старых версиях PHP для работы с файлами и каталогами предусмотрены такие функции как open_dir, read_dir и т.д. Начиная с 5-ой версии PHP для работы с файловой структурой намного удобнее использовать классы SPL (Standard PHP Library). Для наглядности предлагаю разобрать небольшой пример.

Допустим, нам необходимо просканировать дерево каталогов и найти в них все файлы. Затем полученный список нужно отсортировать в алфавитном порядке. Вот как эту задачу можно решить используя SPL:


$dirTree = new RecursiveDirectoryIterator("./testDir");
$sortedFileList = new FileSorterIterator(new RecursiveItertatorIterator($dirTree));

foreach($sortedFileList as $file) {
    echo $file->getFilename() . '<br />';
}


class FileSorterIterator extends SplHeap
{
        
    public function __constructor(Iterator $iterator) {
         foreach ($iterator as $item) {
        	if ($item->isFile()) { 
                  // отсеиваем директории, 
                  // так как в условиях нашей задачи нужно получить только список файлов
              	  $this->insert($item);
        	}
        }

    }

    public function compare($b,$a)
    {
        return strcmp($a->getFilename(), $b->getFilename());
    }
    
}


Как видите, пример получился очень простым. Если в старых версиях PHP приходилось самостоятельно отслеживать указатель на открытую директорию и своевременно его закрывать, то теперь всю «грязную» работу берут на себя классы SPL.

Теперь давайте разберемся какие классы SPL используются в примере:

Класс RecursiveDirectoryIterator
RecursiveDirectoryIterator — это класс SPL который рекурсивно просматривает заданную директорию и составляет дерево всех файлов и директорий. При создании класса нужно указать директорию в которой должен осуществляться поиск.

Для того, чтобы работать с построенным деревом используются стандартные функции интерфейса Iterator, а так же несколько специфичных для данного класса методов.

При работе с данным классом нужно помнить, что функции на подобие foreach перебирают только элементы файловой структуры, находящиеся в корне построенного дерева. Для того, чтобы перебрать элементы расположенные ниже по структуре (имеются в виду вложенные директории) следует использовать специальный класс RecursiveIteratorIterator.

Класс RecursiveIteratorIterator
RecuriveIteratorIterator — это класс созданный для последовательно перебора элементов древовидных итераторов. В нашем примере данный класс используется для того, чтобы обработать файлы расположенные в поддиректориях корневой директории.

Класс FileSorterIterator
FileSorterIterator — это пользовательский класс созданный на базе класса SplHeap. Данный класс нужен для того, чтобы отсортировать файлы в алфавитном порядке. Для этого, используется функция compare, которая содержит условие сортировки, исходя из которого и определяется место элемента в общем массиве.

Исключительные ситуации
Теперь, хочется пару слов сказать о том, что делать если в результате работы указанных классов возникает какая-то ошибка. Например, мы указали для сканирования несуществующую директорию:


$dirTree = new RecursiveDirectoryIterator("./noneExistDirectory");


При возникновении ошибки в работе SPL классов генерируется соответствующее исключение, в случае если эти исключения не обрабатываются, они приводят к останову работы программы в целом. Поэтому лучше предусмотреть обработку наиболее вероятных исключительных ситуаций в программе.

Исключительные ситуации обрабатываются следующим образом:


try{
     $dirTree = new RecursiveDirectoryIterator("./testDasdfsdf");
}catch(Exception $e) {
     var_dump($e->getMessage());
}


В примере вся обработка сводится к выводу сообщения о полученном исключении на экран — RecursiveDirectoryIterator::__construct(./testDasdfsdf): failed to open dir: No such file or directory. В реальном приложении такая обработка, естественно, не подходит, поэтому вместо вывода сообщений на экран стоит придумать, что-то посерьезнее.