preg_last_error()
Узнайте, как preg_last_error() в PHP возвращает код ошибки последнего вызова PCRE, константы ошибок и примеры использования.
Введение
Регулярные выражения — мощный инструмент для работы со строками в PHP. Иногда операции с регулярными выражениями завершаются неудачей из-за некорректных шаблонов или ограничений движка. Функция preg_last_error() помогает выявить такие сбои, возвращая код ошибки последнего вызова функции PCRE.
Синтаксис
preg_last_error(): intФункция не принимает аргументов. Она возвращает целочисленную константу, описывающую причину сбоя последнего вызова функции PCRE — например, preg_match(), preg_match_all(), preg_replace() или preg_split(). Если последний вызов завершился успешно, возвращается PREG_NO_ERROR (0).
Зачем это нужно
Функции PCRE ведут себя нетипично: при сбое они не генерируют исключение. Вместо этого preg_match() возвращает false (не 0 — это означает «нет совпадений»), а preg_replace() возвращает null. Эти возвращаемые значения говорят о том, что пошло не так, но не почему. preg_last_error() заполняет этот пробел, сообщая о конкретной причине.
Именно поэтому необходимо использовать === вместо нестрогого ==: 0 (нет совпадений) и false (ошибка) оба выглядят как «ложные» значения, но означают совершенно разные вещи.
Константы ошибок
preg_last_error() возвращает одну из следующих целочисленных констант. Числовые значения приведены для справки, но в коде следует всегда сравнивать с именованной константой.
| Константа | Значение | Смысл |
|---|---|---|
PREG_NO_ERROR | 0 | Нет ошибки — последняя операция выполнена успешно. |
PREG_INTERNAL_ERROR | 1 | Внутренняя ошибка PCRE (часто связана с некорректным шаблоном). |
PREG_BACKTRACK_LIMIT_ERROR | 2 | Шаблон превысил pcre.backtrack_limit. |
PREG_RECURSION_LIMIT_ERROR | 3 | Шаблон превысил pcre.recursion_limit. |
PREG_BAD_UTF8_ERROR | 4 | Строка не является корректным UTF-8 (при использовании модификатора u). |
PREG_BAD_UTF8_OFFSET_ERROR | 5 | Смещение не соответствует началу корректной кодовой точки UTF-8. |
PREG_JIT_STACKLIMIT_ERROR | 6 | Шаблон исчерпал ограничение стека JIT. |
Начиная с PHP 8.0, preg_last_error_msg() возвращает ту же информацию в виде понятной строки, что удобно для ведения журналов.
Вызов и чтение ошибки
Распространённый реальный сбой — катастрофный возврат (catastrophic backtracking), когда плохо написанный шаблон вынуждает движок перебирать огромное количество путей и достигать лимита возвратов. В примере ниже pcre.backtrack_limit намеренно снижается для воспроизводимости ошибки, после чего проверяется результат.
<?php
// Lower the limit so the failure is easy to reproduce.
ini_set('pcre.backtrack_limit', '100');
$pattern = '/(\w+)*$/'; // nested quantifier — backtracks heavily
$string = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!';
$result = preg_match($pattern, $string, $matches);
if ($result === false) {
echo 'preg_match() failed!' . PHP_EOL;
echo 'Error code: ' . preg_last_error() . PHP_EOL;
echo 'Error message: ' . preg_last_error_msg() . PHP_EOL;
if (preg_last_error() === PREG_BACKTRACK_LIMIT_ERROR) {
echo 'The pattern was too expensive to evaluate.' . PHP_EOL;
}
} elseif ($result === 1) {
echo 'Match found.' . PHP_EOL;
} else {
echo 'No match.' . PHP_EOL;
}Вывод:
preg_match() failed!
Error code: 2
Error message: Backtrack limit exhausted
The pattern was too expensive to evaluate.Код ошибки 2 соответствует PREG_BACKTRACK_LIMIT_ERROR. Принципиально важно, что именно проверка if ($result === false) сигнализирует о реальной ошибке — значение 0 означало бы лишь отсутствие совпадения.
Обнаружение некорректного UTF-8 ввода
При использовании модификатора u (юникод) для строки, которая не является корректным UTF-8, PCRE прерывает выполнение и устанавливает PREG_BAD_UTF8_ERROR:
<?php
$result = preg_match('/./u', "\x80"); // \x80 is not a valid UTF-8 sequence
if ($result === false && preg_last_error() === PREG_BAD_UTF8_ERROR) {
echo 'Invalid UTF-8 input: ' . preg_last_error_msg();
}
// Invalid UTF-8 input: Malformed UTF-8 characters, possibly incorrectly encodedЭто частый источник скрытых ошибок при обработке пользовательских данных, поэтому защита от них является хорошей практикой.
Распространённые ошибки
- Проверяйте немедленно.
preg_last_error()отражает только самый последний вызов PCRE. Любой последующий вызов регулярного выражения перезапишет его, поэтому читайте результат сразу после нужной операции. falseи0. Всегда используйте===.preg_match()возвращает0при «нет совпадений» иfalseпри ошибке — они не взаимозаменяемы.- Сбои
preg_replace(). Когдаpreg_replace()возвращаетnull, стоит вызватьpreg_last_error(), чтобы узнать причину.
Заключение
preg_last_error() превращает непрозрачное возвращаемое значение false в конкретную причину сбоя, делая её незаменимой при отладке регулярных выражений в PHP. Сравнивая возвращаемые значения через === и анализируя код ошибки (или preg_last_error_msg()), можно чётко разделить сбои движка и просто отсутствие совпадений. Функции, сбои которых она отражает, описаны в разделах preg_match(), preg_replace() и preg_split().