最稳方式是用simplexmlelement构造器配合递归,php 5.1.3+原生支持,可正确处理嵌套、重复键、属性与文本混合;避免json_encode+simplexml_load_string绕路及array_walk_recursive遍历。

PHP用SimpleXMLElement递归转数组最稳
直接用 SimpleXMLElement 构造器配合递归是最可靠的方式,不依赖外部库,PHP 5.1.3+ 原生支持,且能正确处理嵌套、重复键、属性与文本混合等场景。
常见错误是试图用 json_encode + simplexml_load_string 绕路——这会丢失类型信息(全变成字符串),也处理不了空数组、数字键作为子节点名等情况。
实操建议:
- 顶层必须是关联数组,否则需先包装成
['root' => $data] - 数字索引数组(如
[1,2,3])要转为同名多个子节点,不能直接设值,得用循环addChild() - 键名含非法 XML 字符(如空格、冒号、尖括号)时,必须预处理(例如替换成下划线或忽略)
- 若数组值为
null,建议转为空字符串或跳过,避免生成<tag></tag>后被某些解析器误判为“有内容”
array_walk_recursive 不适合转XML
它只遍历叶子节点,完全丢弃层级结构和键名上下文,没法区分 ['user'=>['name'=>'a']] 和 ['user_name'=>'a']。强行用会导致 XML 层级塌陷、同名节点无法并列、无法加属性。
典型翻车现象:
输入 ['users'=>['user'=>['id'=>1], 'user'=>['id'=>2]]],用 array_walk_recursive 只能得到两个孤立的 <id>1</id> 和 <id>2</id>,根本拼不出合法结构。
所以别碰这个函数做转换——它连父子关系都维持不了,不是设计用来干这事的。
需要属性时,手动调用addAttribute()
XML 属性(如 <item type="book">PHP Guide</item>)不会自动从数组产生,必须显式添加。常见模式是约定下划线前缀,比如 ['item'=>['_attributes'=>['type'=>'book'], '#text'=>'PHP Guide']],再在递归里识别 _attributes 和 #text 特殊键。
注意点:
-
_attributes必须是关联数组,键为属性名,值为字符串(非字符串会被强制转) -
#text优先级高于子节点:如果同时存在#text和其他键,文本内容会出现在该标签内,其余键仍生成子节点 - 不要用
@attr这类 JSON 常见语法,SimpleXMLElement不认
输出前务必用asXML(),别直接echo $xml
echo $xml 会触发隐式字符串转换,可能漏掉 XML 声明(<?xml version="1.0" encoding="UTF-8"?>),也可能因未设置 header 导致浏览器当 HTML 渲染(中文变乱码)。
正确做法:
- 加声明:用
$xml->asXML()获取完整字符串,开头即含声明 - 设 header:
header('Content-Type: application/xml; charset=utf-8'); - 字符编码必须统一:创建
SimpleXMLElement时默认 UTF-8,确保源数组字符串也是 UTF-8(非 GBK 或 ISO-8859-1) - 如果数组含非法 UTF-8 字节(如从旧数据库读出的乱码),
asXML()会抛DOMException,得提前用mb_convert_encoding($str, 'UTF-8', 'auto')过滤
嵌套深、键名动态、还要混属性的场景,代码量不会少于 30 行——别指望一行函数搞定,老实用递归,边界条件多检查两遍。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











