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: 1xml_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(), чтобы указать пользователям (и вашим журналам) точное место в документе, где произошла ошибка.