Всем привет. Хочу поделиться с вами опытом в парсинге XML файлов размером  до четырёх гигабайт. Что бы это происходило быстро, надо читать файл последовательно, частями, парсить только нужные элементы. В двух словах для быстрого парсинга файлов надо пользоваться XMLReader в связке с yield.  О моей реализации этой связки читайте ниже. XMLReader это единственный класс в PHP, который умеет читать файл по частям. В PHP есть SimpleXML, есть DOMDocument, но они работают с файлом только полностью считывая его с диска, только полностью загружая в оперативную память. И пока мы читаем файл с диска, наш процессор простаивает, пока мы превращаем файл в экземпляр SimpleXML - простаивает база данных, а надо сказать, что XML файл парситься именно для того что бы вставить запись в БД. И все эти простои, это время потраченное в пустую.  Следующее что нам поможет это выражение yield. Прочитали один элемент из файла, распарсили, вернули его с помощью yield, сформировали SQL команду insert, выполнили команду, читаем следующий элемент из файла, и так далее, до победного конца. Ни кто не простаивает, всё примерно одинаково загружено. Теперь сложим всё вместе и получим FastXmlToArray. FastXmlToArray это класс со статическим методом prettyPrint(), на вход можно подать или ссылку на XML файл (путь к файлу) или собственно XML строку. На выходе будет PHP массив со всеми атрибутами и значениями корневого элемента и всех вложенных элементов. Вывод в консоль Killer feature этого класса это статический метод extractElements(), который принимает XMLReader, а выдаёт всё тоже самое: массив со всеми атрибутами и значениями этого элемента и всех вложенных элементов. Существенная разница, в том что prettyPrint() обрабатывает сразу корневой элемент XML документа (по сути весь файл), а extractElements() работает с произвольным элементом (часть файла), из XML документа можно передать любой элемент. То есть не надо весь файл загружать в парсер, что бы этот файл распарсить, можно дочитать до нужного элемента, и уже только его парсить, обработать результат парсинга, и вычитать ещё часть файла, ещё один элемент, и снова обработать. Такая потоковая обработка даёт более плавную загрузку сервиса парсинга и сервиса СУБД. Использование extractElements() снимает зависимость от размера файла. Проверим на практике. Нагенерим файлы разного размера: Размеры файлов: Получились файлы с размерами полкилобайта, полмегабайта и полгигабайта. Замерим время парсинга первого элемента: Результаты: Время доступа к первому элементу составило: 156,600 нс,  133,700 нс,  122,100 нс. Как видим время отличается не сильно, учитывая что операционная система на которой выполняется PHP код, как правило это не система реального времени, то можно сказать что время парсинга первого элемента из файла, не зависит от размеров файла. Теперь разберёмся с тем как писать код с использованием FastXmlToArray. Будем парсить что-то такое: Допустим нас во всём документе интересуют только элементы CARPLACE. Переведём XMLReader на первый элемент CARPLACE Пройдёмся по всем элементам CARPLACE, пока не перейдём к элементу с другим именем или пока документ не кончиться Что мы тут делаем ?  С помощью FastXmlToArray::extractElements() получаем список элементов со всеми значениями и атрибутами(в этом примере список всего из одной позиции) С помощью FastXmlToArray::createTheHierarchyOfElements() формируем иерархию элементов как они есть в исходном документе, иерархию будет в формате массива (в этом примере из одного элемента и его атрибутов). С помощью FastXmlToArray::composePrettyPrintByXmlElements() можно сформировать более компактное представление, но работать с ним не так удобно. Выводим в консоль получившийся массив, или можем выполнить любую обработку над сформированным массивом. Вместо echo можно, делать yield и отдавать массив на обработку наружу, я в своём парсере ФИАС ГАР так и делаю. Возвращаю через yield массив, и делаю insert в базу. Проматываем "файл" до следующего элемента или до конца "файла" В консоли будет что-то такое: Пример запроса сведений, пришедший по СМЭВу, нас тут интересует только элемент ns:Query Код будет аналогичным: Вывод в консоль: На самом деле, конечно, нас интересует только <ns:SearchNumber Number="22RU006228DV"/>, и в коде продакшена было бы while ($reader->name === 'ns:SearchNumber'), ради наглядности я привёл получение кусочка побольше. Прежде чем переписать свою библиотеку для работы с XML, я посмотрел что нам может предложить Open Source.  На Packagist под сотню пакетов, я посмотрел первые 30, посмотрел в исходники, везде примерно одно и тоже, но время работы отличалось в разы, как позже оказалось это была ошибка моего бенчмарка.  На самом деле время везде примерно одно и тоже. С той разницей, что функции работают быстрей статических методов, а статические методы работают быстрее методов экземпляра класса, а самые медленные это просто PHP скрипты. За время разработки я перепробовал все 4 варианта, и один и тот же код работает в разных "форматах" с разницей в единицы микросекунд, если вам это важно, то пишите свой конвертор XML в процедурном стиле, выиграете пару микросекунд. Мои замеры быстродействия: От запуска к запуску числа отличаются, но общая картина примерно такая. Мой use case заключался в том, что бы 280 гигабайт XML файлов превратить в базу данных Федеральной Информационной Адресной системы (БД ФИАС). Надеюсь, теперь понятно почему меня волновало время парсинга XML файлов. Что удивительно это то, что 280 гигабайт XML файлов превратить в 190 гигабайт базы данных, такое чувство что у СУБД нет ни какой оптимизации, если из XML выкинуть имена элементов и имена атрибутов и всю разметку, то что там останется ? На мой взгляд объём должен был сократиться в два раза, хотя бы, но нет. 190 гигабайт это без индексов, с индексами наверное все 220 будут. В первых версиях парсер жрал по 4 гига оперативы, грузил БД на 25% процессора, сколько процесс PHP отъедал оперативки я уже не помню. Вставка 100 000 записей занимала от 2 минут, чтение файла могло затянуться на 10 минут. Последняя версия парсера ровно каждые 9 секунд вставляет очередные 100 0000 записей, открытие файла занимает ноль секунд. PHP и БД каждый отъедают не больше 8 мегабайт оперативки и не больше 12% процессора. Но даже при этих условиях, добавление полной базы ГАР заняло 40 часов. Полтора миллиарда записей за один день и 16 часов (24+16=40), 40 часов это очень долго, из оптимизаций в голову приходит только асинхронности добавить, что бы один поток парсил XML, а другой поток отправлял данные в СУБД. Ваши предложения ?  Если вам хочется попробовать этот парсер в деле, то вы можете установить пакет через Композер Больше информации в репозитории в README.md Статья написана на 5 версию библиотеки, в 6 версии были добавлены классы и переименованы методы, суть осталась прежней, добавились приятные возможности, подробности в репозитории в README.md.  программист эникейщик