W3docs

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_ERROR0Нет ошибки — последняя операция выполнена успешно.
PREG_INTERNAL_ERROR1Внутренняя ошибка PCRE (часто связана с некорректным шаблоном).
PREG_BACKTRACK_LIMIT_ERROR2Шаблон превысил pcre.backtrack_limit.
PREG_RECURSION_LIMIT_ERROR3Шаблон превысил pcre.recursion_limit.
PREG_BAD_UTF8_ERROR4Строка не является корректным UTF-8 (при использовании модификатора u).
PREG_BAD_UTF8_OFFSET_ERROR5Смещение не соответствует началу корректной кодовой точки UTF-8.
PREG_JIT_STACKLIMIT_ERROR6Шаблон исчерпал ограничение стека 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().

Практика

Практика
Что делает функция 'preg_last_error' в PHP?
Что делает функция 'preg_last_error' в PHP?
Was this page helpful?