fnmatch()
Функция fnmatch() в PHP проверяет совпадение строки с шаблоном подстановки оболочки. Узнайте синтаксис, символы подстановки и флаги.
Что такое функция fnmatch()?
Функция fnmatch() проверяет, соответствует ли строка шаблону подстановки оболочки — такому же, какой вы вводите в терминале, например *.txt или image-?.png. Она возвращает boolean, поэтому чаще всего используется для фильтрации имён файлов или других строк без написания полного регулярного выражения.
Несмотря на название, fnmatch() никогда не обращается к файловой системе. Она только сравнивает шаблон со строкой, которую вы передаёте, поэтому работает с любым текстом, а не только с реальными файлами.
На этой странице рассматриваются сигнатура функции, символы подстановки, которые она понимает, необязательные флаги и практические случаи, когда она превосходит как glob(), так и регулярные выражения.
Синтаксис
fnmatch(string $pattern, string $filename, int $flags = 0): bool$pattern— шаблон подстановки оболочки для сопоставления.$filename— проверяемая строка (необязательно должна быть реальным файлом).$flags— необязательные битовые флаги, изменяющие поведение сопоставления (см. Флаги).
Функция возвращает true, если $filename соответствует $pattern, и false в противном случае.
Базовый пример
Здесь myfile.txt соответствует *.txt, поэтому выполняется первая ветка и выводится The string matches the pattern!. Замените строку на myfile.csv — и сопоставление завершится неудачей.
Символы подстановки
fnmatch() понимает стандартные символы подстановки оболочки. Точное знание того, что делает каждый из них, является ключом к правильному использованию функции:
| Символ подстановки | Значение | Пример шаблона | Соответствует | Не соответствует |
|---|---|---|---|---|
* | Любая последовательность символов (включая пустую) | *.log | error.log, .log | error.txt |
? | Ровно один символ | file?.txt | file1.txt | file12.txt |
[...] | Один символ из набора | image.[jp]ng | image.jng, image.png | image.gng |
[!...] | Один символ, не входящий в набор | [!0-9]* | abc | 1abc |
Следующий пример демонстрирует каждый символ подстановки, чтобы вы могли увидеть их рядом:
<?php
var_dump(fnmatch("*.log", "error.log")); // bool(true) — * matches "error"
var_dump(fnmatch("file?.txt", "file1.txt")); // bool(true) — ? matches one char
var_dump(fnmatch("file?.txt", "file12.txt"));// bool(false) — ? matches only ONE char
var_dump(fnmatch("img.[jp]ng", "img.png")); // bool(true) — p is in [jp]
var_dump(fnmatch("[!0-9]*", "abc")); // bool(true) — first char is not a digit
var_dump(fnmatch("[!0-9]*", "1abc")); // bool(false) — first char IS a digitФлаги
Третий аргумент принимает одну или несколько следующих констант, объединённых оператором побитового ИЛИ (|):
| Флаг | Эффект |
|---|---|
FNM_NOESCAPE | Обрабатывать обратную косую черту (\) буквально, а не как управляющий символ. |
FNM_PATHNAME | Косая черта (/) в строке должна совпадать с буквальным / — * и ? не будут её сопоставлять. |
FNM_PERIOD | Начальная точка в строке должна совпадать явно; * и ? не будут её сопоставлять. |
FNM_CASEFOLD | Сопоставление без учёта регистра. |
FNM_CASEFOLD — это флаг, к которому вы будете обращаться чаще всего:
<?php
var_dump(fnmatch("*.PNG", "photo.png")); // bool(false) — case differs
var_dump(fnmatch("*.PNG", "photo.png", FNM_CASEFOLD)); // bool(true) — case ignoredС FNM_PATHNAME символ подстановки * останавливается на разделителях каталогов, что удобно при сопоставлении целых путей:
<?php
var_dump(fnmatch("src/*.php", "src/index.php")); // bool(true)
var_dump(fnmatch("src/*.php", "src/lib/db.php")); // bool(true) — * crosses the slash
var_dump(fnmatch("src/*.php", "src/lib/db.php", FNM_PATHNAME));// bool(false) — * cannot cross "/"Практический пример использования: фильтрация списка файлов
Распространённая задача — оставить только те элементы, которые соответствуют шаблону. Поскольку fnmatch() работает с обычными строками, она хорошо сочетается с array_filter():
<?php
$files = ["report.pdf", "notes.txt", "draft.txt", "image.png"];
$textFiles = array_filter($files, fn($file) => fnmatch("*.txt", $file));
print_r(array_values($textFiles));Это выводит:
Array
(
[0] => notes.txt
[1] => draft.txt
)fnmatch() vs. glob() vs. регулярные выражения
Эти три инструмента частично перекрываются, поэтому важно выбрать правильный:
- Используйте
glob(), когда хотите прочитать реальные файлы с диска, соответствующие шаблону. Она обращается к файловой системе и возвращает найденные пути. - Используйте
fnmatch(), когда у вас уже есть строки (имена файлов, ключи, метки) в памяти и нужна только проверка true/false по шаблону подстановки. - Используйте
preg_match(), когда нужна вся мощь регулярных выражений — группы захвата, чередование, кванторы — которые простые символы подстановки не могут выразить.
Подводные камни
- Это не файловая система.
fnmatch()не проверяет существование файла; она только сравнивает строки. Для доступа к диску используйтеglob(). - Доступность. В сборках Windows до PHP 7.2 функция
fnmatch()может быть недоступна. Оберните вызовы вfunction_exists('fnmatch'), если необходима поддержка таких сред. - Шаблоны — это не регулярные выражения.
*означает «любые символы», а не «ноль или более повторений предыдущего токена». Если вы напишетеa+, ожидая квантор регулярного выражения, он будет трактоваться как два буквальных символаaи+. - Скрытые файлы. По умолчанию
*соответствует начальной точке, поэтому*соответствует.gitignore. ДобавьтеFNM_PERIOD, если хотите пропускать файлы с точкой, как это делает оболочка.
Заключение
fnmatch() — самый простой способ проверить строку на соответствие шаблону подстановки в стиле оболочки в PHP. Используйте её, когда нужна быстрая, читаемая фильтрация имён файлов без накладных расходов регулярного выражения — и помните о её дополнениях: glob() для чтения файлов с диска и preg_match() для всего более сложного, чем символы подстановки.