W3docs

xml_get_error_code()

Функция PHP xml_get_error_code(): синтаксис, возвращаемое значение и перевод кода ошибки Expat в читаемое сообщение с xml_error_string().

Функция xml_get_error_code() — это встроенная функция PHP, которая возвращает код ошибки XML-парсера. При разборе XML с помощью расширения XML Parser (Expat) функции разбора возвращают false в момент возникновения ошибки — однако само по себе false не говорит вам, что именно пошло не так. xml_get_error_code() возвращает числовой код, описывающий последнюю ошибку, который затем можно перевести в понятное человеку сообщение с помощью xml_error_string().

На этой странице описаны синтаксис функции, возвращаемое значение, способ преобразования кода в сообщение, а также подводный камень, на который натыкается большинство разработчиков: возвращаемый код является кодом ошибки Expat, а не константой XML_OPTION_*, как можно было бы ожидать.

Синтаксис

xml_get_error_code(XMLParser $parser): int

$parser — парсер, созданный функцией xml_parser_create() (или xml_parser_create_ns()). В PHP 8.0+ это объект типа XMLParser; в PHP 7.x и более ранних версиях это был resource. Код в этой главе работает в обоих случаях.

Возвращаемое значение

Функция возвращает целочисленный код ошибки:

  • 0 (константа XML_ERROR_NONE) означает отсутствие ошибки — разбор прошёл успешно.
  • Любое ненулевое значение указывает на тип сбоя. Передайте его в xml_error_string(), чтобы получить читаемое описание, а в xml_get_current_line_number() — чтобы найти место ошибки.

Всегда сначала проверяйте возвращаемое значение функции разбора (xml_parse() / xml_parse_into_struct()); вызывайте xml_get_error_code() только после того, как она вернула false.

Полный рабочий пример

В примере ниже выполняется разбор намеренно некорректной XML-строки (закрывающий тег не соответствует открывающему), после чего выводятся код ошибки, её сообщение и номер строки. Поскольку XML встроен в виде строки, вы можете скопировать и запустить этот код — никакие файлы не нужны.

<?php
$broken = "<note><to>Ann</from></note>";   // </from> should be </to>

$parser = xml_parser_create();
if (!xml_parse_into_struct($parser, $broken, $values)) {
    $code = xml_get_error_code($parser);
    echo "Error code:  $code\n";
    echo "Message:     " . xml_error_string($code) . "\n";
    echo "On line:     " . xml_get_current_line_number($parser) . "\n";
}
xml_parser_free($parser);

Вывод:

Error code:  76
Message:     Mismatched tag
On line:     1

xml_parse_into_struct() возвращает false, поэтому мы вызываем xml_get_error_code() и передаём результат прямо в xml_error_string(), чтобы получить сообщение "Mismatched tag".

Подводный камень: код является кодом Expat

Возникает соблазн сравнивать результат с константами вроде XML_ERROR_TAG_MISMATCH в конструкции switch:

switch ($code) {
    case XML_ERROR_TAG_MISMATCH:  // value 7
        // ...
}

Но этот ветвь никогда не совпадёт. Парсер Expat возвращает 76 для несовпадающего тега, тогда как XML_ERROR_TAG_MISMATCH — это константа 7; они принадлежат разным схемам нумерации, поэтому сравнение молча завершается неудачей. Надёжный подход — всегда преобразовывать код в текст с помощью xml_error_string(), а не сравнивать сырые числа:

<?php
$samples = [
    'good'      => "<note><to>Ann</to></note>",
    'mismatch'  => "<note><to>Ann</from></note>",
    'truncated' => "<note><to>Ann",
];

foreach ($samples as $label => $xml) {
    $parser = xml_parser_create();
    $ok = xml_parse_into_struct($parser, $xml, $values);
    $code = xml_get_error_code($parser);
    printf("%-9s -> code %d (%s)\n", $label, $code, xml_error_string($code) ?: 'OK');
    xml_parser_free($parser);
}

Вывод:

good      -> code 0 (No error)
mismatch  -> code 76 (Mismatched tag)
truncated -> code 5 (Invalid document end)

Код 0 (XML_ERROR_NONE) подтверждает, что документ разобран без ошибок — именно это и выдаёт корректный образец good.

Отображение ошибки пользователю

В реальном приложении — например, в обработчике загруженного XML-файла — вы обычно записываете технические подробности в журнал и показываете пользователю понятное сообщение:

$parser = xml_parser_create();
$xml    = file_get_contents($_FILES['xml_file']['tmp_name']);

if (!xml_parse_into_struct($parser, $xml, $values)) {
    $code = xml_get_error_code($parser);
    $line = xml_get_current_line_number($parser);

    // For the logs / developers:
    error_log("XML parse failed on line $line: " . xml_error_string($code));

    // For the user:
    $userMessage = "We couldn't read that file — please check it is valid XML.";
}
xml_parser_free($parser);

Когда использовать (и когда не стоит)

xml_get_error_code() относится к расширению XML Parser на основе Expat — того же семейства, что xml_parser_create() и xml_parse_into_struct(). Используйте её, когда выполняете событийный/потоковый разбор с помощью этого расширения и вам нужно реагировать на сбой.

Если вы разбираете XML с помощью SimpleXML или DOM, эта функция неприменима — они используют API ошибок libxml. В этом случае воспользуйтесь libxml_get_last_error() (предварительно вызвав libxml_use_internal_errors(true)), чтобы узнать, что пошло не так. Описание этого рабочего процесса см. в обзоре SimpleXML.

Заключение

xml_get_error_code() возвращает числовой код ошибки Expat для последнего сбоя экземпляра XML Parser. Надёжный шаблон использования: проверьте возвращаемое значение функции разбора, и если оно равно false, вызовите xml_get_error_code() и передайте результат в xml_error_string() для получения читаемого сообщения — не сравнивайте сырой код с константами XML_ERROR_*, поскольку нумерация Expat не совпадает с ними. Используйте вместе с xml_get_current_line_number(), чтобы указать пользователям (и вашим журналам) точное место в документе, где произошла ошибка.

Практика

Практика
Какой правильный способ получить код ошибки XML-документа в PHP?
Какой правильный способ получить код ошибки XML-документа в PHP?
Was this page helpful?