Компонент Finder

Дата обновления перевода 2023-01-20

Компонент 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 в качестве дополнительного имени <.

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

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

По умолчанию, 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.

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

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

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

6.2

Методы sortByCaseInsensitiveName(), sortByExtension() и sortBySize() были представлены в Symfony 6.2.

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) {
    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();

    // ...
}