为何DOMDocument解析120MB XML耗时80分钟,XMLParser仅需10秒?
核心差异来源于两者的解析模式、数据存储结构完全不同,结合你的测试数据(DOM加载文件仅2.3秒,但整体耗时80分钟),具体原因如下:
解析模式本质不同
DOMDocument是DOM树解析,会将整个XML文档加载到内存中,构建一个完整的层级对象树——每个元素、属性、文本节点都会被实例化为DOMNode或其子类对象,同时维护节点间的父子、兄弟引用关系。120MB的XML通常包含数百万级的节点,构建这棵树的后续操作(遍历节点、访问节点内容、处理节点属性)会因为对象实例的开销被无限放大,这也是你看到“加载文件快,但整体耗时极长”的原因:大部分时间都花在处理DOM对象树上,而非文件加载阶段。
而XMLParser(xml_parse_into_struct)是SAX风格的事件驱动解析,属于流式处理:它逐行读取XML内容,按元素的开始、结束事件将数据转换为PHP原生数组,不需要构建完整的对象树,只是把XML的结构映射为数组的嵌套/扁平结构,内存中存储的是轻量化的数组数据,而非复杂的对象实例。对象vs数组的性能开销差
DOM的每个节点都是独立的PHP对象,每个对象包含大量内置属性(节点类型、命名空间、父节点指针等)和方法,对象的实例化、属性访问、内存管理(引用计数、垃圾回收)的开销在节点数量极多时会呈指数级增长。比如访问$domNode->nodeValue的开销远高于访问数组元素$array['value'],当你需要遍历处理成千上万的item节点时,累计的时间差会从秒级飙升到分钟级。
而xml_parse_into_struct生成的数组是PHP原生数据结构,内存布局紧凑,访问和操作的速度远快于DOM对象,垃圾回收的压力也小得多。内存使用与碎片化影响
虽然两者都设置了3G内存限制,但DOM树的实际内存占用远高于XMLParser生成的数组:DOM节点除了存储数据,还要维护大量元信息和引用关系,容易造成内存碎片化,PHP的垃圾回收机制在处理大量DOM对象时会频繁触发,进一步拖慢整体速度。而数组的内存使用更高效,碎片化程度低,对垃圾回收的影响极小。SimpleXML的表现佐证
SimpleXML本质是DOM的上层封装,底层依然依赖DOM树实现,只是提供了更简洁的访问语法,因此性能和DOMDocument相当甚至更慢——多了一层封装的额外开销,这也和你的测试结果一致。
内容的提问来源于stack exchange,提问作者hanshenrik

