Я провел немало исследований и пришел к выводу, что лучше всего реализовать все с помощью старого scandir
а также foreach
вместо того, чтобы идти по пути итератора.
По сути, мне нужен способ получения содержимого каталогов — опционально отсортированный, опционально рекурсивный и опционально отфильтрованный по имени файла. Какая IMO — самая базовая функциональность, которую вы ожидаете от любого довольно сложного обходчика файловой системы.
Ну так получается, ни RecursiveDirectoryIterator
ни FilesystemIterator
поддержка сортировки или же фильтрация. Нужно обернуть их в классе, который расширяет ArrayObject
добиться сортировки — или FilterIterator
для фильтрации. Так что для достижения обоих нужно написать два классы, упаковывающие все в несметное число уровней, и код в конечном итоге выглядит странным и слишком сложным.
Я что-то упускаю из-за подхода, или я должен поцарапать свой прогресс и переписать все в 20+ строк в простой тупой if/else/foreach
код?
Итераторы, найденные в SPL, не все «готовы к работе». Это базовые блоки, которые можно использовать для создания чего угодно. FileSystemIterator
может иметь некоторую базовую функциональность для фильтрации, но вы хотите создать больше самостоятельно, и это довольно легко сделать.
Преимущество использования итераторов, таких как FilesystemIterator
и таково то, что вы отделяете логику обхода от логики фильтра от логики сортировки от бизнес-логики.
Скажем, у вас есть следующее:
$dir = opendir('.');
while (($file = readdir($dir)) !== false) {
// business logic
}
и позже вы решите фильтровать только файлы MP3:
$dir = opendir('.');
while (($file = readdir($dir)) !== false) {
if (preg_match('|\.mp3$|i', $file)) {
// business logic
}
}
Но как насчет фильтрации файлов MP3 и JPG или файлов MP3, размер которых меньше 5 МБ, и всего недельной давности, и файлов JPG, размер которых превышает 2 МБ, а как насчет нескольких каталогов или рекурсивных каталогов и т. Д.? Ваша петля «foreach / while» становится кошмаром, хотя все начиналось довольно мило.
Отделение логики обхода от бизнес-логики означает, что ее проще поддерживать, тестировать и даже повторно использовать:
$it = new DirectoryIterator("."); // Dir iterator
$it = new RegexIterator($it, "|\.mp3$|i"); // filter MP3's
$it = new FilesizeIterator($it, "<6MB"); // Only less than 6MB
$it = new LimitIterator($it, 0, 100); // First 100 items only
foreach ($it as $file) {
// extrabonus: $file is a SplFileInfo object
}
Легко представить, как мы могли бы «встроить» логику итератора в более сложные примеры, и мы можем использовать такие вещи, как RegexIterator
для других вещей, кроме имен файлов тоже. Это также намного легче проверить, потому что нам нужно только проверить, regexFilterIterator
правильно фильтрует регулярные выражения, вот и все.
Сортировка и тому подобное также могут быть добавлены, основываясь на том, что вам нравится, но все же: никаких изменений в вашей бизнес-логике, и при этом все еще оторвано от всей другой логики.
Взгляните на Symfony2 Finder
Компонент: он использует много итераторов для фильтрации и сортировки элементов.
Других решений пока нет …