Компонент Finder

Дата обновления перевода 2024-07-03

Компонент Finder

Компонент Finder находит файлы и каталоги, основываясь на разных критериях (имени, размере файла, времени изменения и др.) через текучий интерфейс.

Установка

1
$ composer require symfony/finder

Note

Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно подключить файл vendor/autoload.php в вашем коде для включения механизма автозагрузки классов, предоставляемых Composer. Детальнее читайте в этой статье.

Применение

Класс Finder находит файлы и/или каталоги:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Symfony\Component\Finder\Finder;

$finder = new Finder();
// найти все файлы текущего каталога
$finder->files()->in(__DIR__);

// проверить, есть ли результаты поиска
if ($finder->hasResults()) {
    // ...
}

foreach ($finder as $file) {
    $absoluteFilePath = $file->getRealPath();
    $fileNameWithExtension = $file->getRelativePathname();

    // ...
}

Переменная $file является экземпляром SplFileInfo, который расширяет собственный SplFileInfo PHP, чтобы предоставить методы для работы с относительными путями.

Caution

Объект Finder не перезагружает внутреннее состояние автоматически. Это означает, что вам нужно создать новый экземпляр, если вы не хотите получить смешнанный результат.

Поиск файлов и каталогов

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

Локация

Локация - единственный обязательный критерий. Она сообщает Finder, какой каталог использовать для поиска:

1
$finder->in(__DIR__);

Искать в нескльких локациях, изменяя вызов на in():

1
2
3
4
5
// искать внутри *обоих* каталогов
$finder->in(array(__DIR__, '/elsewhere'));

// то же, что и выше
$finder->in(__DIR__)->in('/elsewhere');

Используйте * в качестве символа-заполнителя, чтобы искать в каталогах, соответствующих паттерну (каждый паттерн должен разрешать хотя бы один путь каталога):

1
$finder->in('src/Symfony/*/*/Resources');

Исключите каталоги, совпадающие с методом exclude():

1
2
// каталоги, переданные в качестве аргумента, должны быть связаны с теми, что определены в методе in()
$finder->in(__DIR__)->exclude('ruby');

Также возможно игнорировать каталоги, на чтение которых у вас нет разрешения:

1
$finder->ignoreUnreadableDirs()->in(__DIR__);

Так как Finder использует PHP итераторы, вы можете передать любой URL, поддерживаемый PHP-оберткой для протоколов типа URL (ftp://, zlib://, etc.):

1
2
3
4
5
// всегда добавляйте закрывающий слеш, когда ищете dir корна FTP
$finder->in('ftp://example.com/');

// вы можете также искать в каталоге FTP
$finder->in('ftp://example.com/pub/');

И это также работает с потоками, определёнными пользователями:

1
2
3
4
5
6
7
8
9
10
11
use Symfony\Component\Finder\Finder;

// зарегистрировать обертку 's3://' с официальным AWS SDK
$s3Client = new Aws\S3\S3Client([/* config options */]);
$s3Client->registerStreamWrapper();

$finder = new Finder();
$finder->name('photos*')->size('< 100K')->date('since 1 hour ago');
foreach ($finder->in('s3://bucket-name') as $file) {
    // ... сделать что-то с файлом
}

See also

Прочтите документацию PHP-потоки, чтобы узнать, как создавать собственные потоки.

Файлы или каталоги

По умолчанию, Finder возвращает и файлы, и каталоги. Если вам нужны только файлы, или только каталоги, используйте методы files() и directories():

1
2
3
4
5
// искать только файлы; игнорировать каталоги
$finder->files();

// искать только каталоги; игнорировать файлы
$finder->directories();

Если вы хотите следовать символьным ссылкам, используйте метод followLinks():

1
$finder->files()->followLinks();

Файлы контроля версий

Системы контроля версий (или сокращённо "VCS"), такие как Git и Mercurial, создают специальные файлы для хранения своих метаданных. Эти файлы игнорируются при поиске файлов и каталогов по умолчанию, но вы можете изменить это методом ignoreVCS():

1
$finder->ignoreVCS(false);

Если поисковый каталог и его подкаталоги содержат файлы .gitignore, вы можете повторно использовать эти правила, чтобы исключить файлы и каталоги из результатов, методом ignoreVCSIgnored():

1
2
// исключить files/directories, совпадающие с паттернами .gitignore
$finder->ignoreVCSIgnored(true);

Правила каталога всегда главенствуют над правилами родительских каталогов.

Note

Git ищет файлы .gitignore, начиная с корневого каталога хранилица. Поведение Symfony Finder отличается - он ищет файлы .gitignore, начиная с каталога, используемого для поиска файлов/каталогов. Чтобы соответствовать поведению Git, вам нужно ясно искать из корня хранилища Git.

Имя файла

Найдите файлы по имени методом name():

1
$finder->files()->name('*.php');

Метод name() принимает глобальные выражения, строки, регулярные выражения и массивы глобальных или регулярных выражений:

1
$finder->files()->name('/\.php$/');

Множество имен файлов может быть определено путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->files()->name('*.php')->name('*.twig');

// то же, что и выше
$finder->files()->name(['*.php', '*.twig']);

Метод notName() исключает файлы, совпадающие со схемой:

1
$finder->files()->notName('*.rb');

Множество имен файлов может быть исключено путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->files()->notName('*.rb')->notName('*.py');

// то же, что и выше
$finder->files()->notName(['*.rb', '*.py']);

Содержание файла

Найдите файлы по содержанию, методом contains():

1
$finder->files()->contains('lorem ipsum');

Метод contains() принимает строки или регулярные выражения:

1
$finder->files()->contains('/lorem\s+ipsum$/i');

Метод notContains() исключает файлы, содержащие заданный паттерн:

1
$finder->files()->notContains('dolor sit amet');

Путь

Найдите файлы и папки по пути, методом path():

1
2
3
4
// сопоставляет файлы, содержащие "data" где-либо в их путях (файлах или каталогах)
$finder->path('data');
// например, это будет соответстсовать data/*.xml и data.xml, если они существуют
$finder->path('data')->name('*.xml');

Используйте слеш вправо (т.e. /) в качестве разделителя каталогов на всех платформах, включая Windows. Компонент проведет необходимые преобразования внутренне.

Метод path() принимает строку, регулярное выражение или массив строк или регулярных выражений:

1
2
$finder->path('foo/bar');
$finder->path('/^foo\/bar/');

Множество путей может быть определено путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->path('data')->path('foo/bar');

// то же, что и выше
$finder->path(['data', 'foo/bar']);

Внутренне, строки преобразуются в регулярные выражения, экранируя слеши и добавляя разграничители:

??????????? ?????? ???????????? ?????????? ?????????
dirname /dirname/
a/b/c /a\/b\/c/

Метод notPath() исключает файлы по пути:

1
$finder->notPath('other/dir');

Множество путей можно исключить путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->notPath('first/dir')->notPath('other/dir');

// то же, что и выше
$finder->notPath(['first/dir', 'other/dir']);

Размер файла

Найдите файлы по размеру, методом size():

1
$finder->files()->size('< 1.5K');

Ограничьте по диапазону размера, создав цепочку вызовов или передав массив:

1
2
3
4
$finder->files()->size('>= 1K')->size('<= 2K');

// то же, что и выше
$finder->files()->size(['>= 1K', '<= 2K']);

Оператор сравнения может быть чем-либо из следующего: >, >=, <, <=, ==, !=.

Целевое значение может использовать величины килобайтов (k, ki), мегабайтов (m, mi), или гигабайтов (g, gi). Те, что имеют суффикс i, используют соответствующую версию 2**n в соответствии со стандартом IEC.

Дата файла

Найдите файлы по датам последних изменений, методом date() :

1
$finder->date('since yesterday');

Ограничьте по диапазноу данных путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->date('>= 2018-01-01')->date('<= 2018-12-31');

// то же, что и выше
$finder->date(['>= 2018-01-01', '<= 2018-12-31']);

Оператор сравнения может быть любым из следующих: >, >=, <, <=, ==. Вы можете также использовать since или after в качестве дополнительного имени >, и until или before в качестве дополнительного имени <.

Целевое значение может быть любыми данными, поддерживаемыми функцией 3e58f474762cc1c5095e917255f3d98f65e2bfef.

Глубина каталога

По умолчанию, Finder траверсирует каталоги в обратном порядке. Ограничьте глубину траверсирования методом depth():

1
2
3
// это будет рассматривать только файлы/каталоги, которые являются прямыми дочерними
$finder->depth('== 0');
$finder->depth('< 3');

Ограничьте по диапазону глубины путем создания цепочки вызовов или передачи массива:

1
2
3
4
$finder->depth('> 2')->depth('< 5');

// то же, что и выше
$finder->depth(['> 2', '< 5']);

Пользовательское фильтрование

Чтобы отфильтровать результаты по собственной стратегии, используйте filter():

1
2
3
4
5
6
7
8
$filter = function (\SplFileInfo $file)
{
    if (strlen($file) > 10) {
        return false;
    }
};

$finder->files()->filter($filter);

Метод filter() берёт Closure в качестве аргумента. Для каждого совпадающего файла, он вызываетя с файлом SplFileInfo в качестве экземпляра. Файл исключается из набора результатов, если замыкание возвращает false.

Метод filter() содержит второй необязательный аргумент для обрезки каталогов. Если установить значение true, этот метод полностью пропускает исключенные каталоги вместо того, чтобы обходить всю структуру файлов/каталогов и исключать их позже. При использовании замыкания, верните false для каталогов, которые вы хотите обрезать.

Раннее обрезание каталогов может значительно повысить производительность в зависимости от сложности иерархии файлов/каталогов и количества исключаемых каталогов.

Сортировка результатов

Отсортируйте результаты по имени или типу (сначала каталоги, потом - файлы):

1
2
3
4
5
$finder->sortByName();
$finder->sortByCaseInsensitiveName();
$finder->sortByExtension();
$finder->sortBySize();
$finder->sortByType();

Tip

По умолчанию, метод sortByName() использует PHP-функцию strcmp (например, file1.txt, file10.txt, file2.txt). Передайте true в качестве ее аргумента, чтобы использовать вместо этого алгоритмы природного порядка сортировки PHP (например, file1.txt, file2.txt, file10.txt).

Метод sortByCaseInsensitiveName() использует нечувствительную к регистру PHP-функцию strcasecmp. Передайте true как её аргумент, чтобы исполььзовать вместо этого нечувствительный к регистру PHP-алгоритм природного порядка сортировки (т.е. PHP-функцию strnatcasecmp).

Отсортируйте файлы и каталоги по последнему доступу, изменению или времени изменения:

1
2
3
4
5
$finder->sortByAccessedTime();

$finder->sortByChangedTime();

$finder->sortByModifiedTime();

Вы также можете определить собственный алгоритм сортировки методом sort():

1
2
3
$finder->sort(function (\SplFileInfo $a, \SplFileInfo $b): int {
    return strcmp($a->getRealPath(), $b->getRealPath());
});

Вы можете поменять порядок любой сортировки, используя метод reverseSorting():

1
2
// результаты будут отсортированы "от Z до A" вместо "от A до Z" по умолчанию
$finder->sortByName()->reverseSorting();

Note

Заметьте, что методы sort* должны получить все совпадающие элементы, чтобы работать. Для больших итераторов это будет медленно.

Преобразование результатов в массивы

Экземпляр Finder - это PHP-класс IteratorAggregate. Поэтому, в дополнение к итерации foreach поверх результатов Finder, вы также можете преобразовать их в массив с помощью функции iterator_to_array, или получить количество объектов с помощью iterator_count.

Если вы вызовете метод in() более одного раза, чтобы произвести поиск по множеству локаций, передайте false в качестве второго параметра iterator_to_array, чтобы избежать проблем (отдельный итератор создается для каждой локации, и если вы не передадите false к iterator_to_array, используются ключи наборов результатов, и некоторые из них могут быть дублированы, а их значения - переопределены).

Чтение содержания возвращённых файлов

Содержание возвращённых файлов можно прочитать с помощью getContents():

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Finder\Finder;

$finder = new Finder();
$finder->files()->in(__DIR__);

foreach ($finder as $file) {
    $contents = $file->getContents();

    // ...
}