PHP 5中含重复source节点的SOAP调用实现方案问询
我之前在PHP 5里搞SOAP调用的时候,也踩过这个重复节点的大坑——毕竟PHP数组不允许重复键,直接写多个source键肯定不行,而且随便转对象还容易报那些属性不存在的错。给你几个亲测有效的解决方法:
方法一:用索引数组包裹多个source项
这是最直接的方案,PHP的SOAP扩展会自动把索引数组转换成重复的同名子节点。你只需要把单个source的数组改成一个包含多个source数组的索引数组就行:
$data = [ 'sources' => [ 'source' => [ ['name' => 'somename1', 'id' => 'someid1'], ['name' => 'somename2', 'id' => 'someid2'] ] ] ];
当你把这个数组传给__soapCall时,SOAP扩展会自动解析成你要的XML结构:
<sources> <source> <name>somename1</name> <id>someid1</id> </source> <source> <name>somename2</name> <id>someid2</id> </source> </sources>
原理很简单:SOAP扩展识别到source的值是索引数组(不是关联数组)时,就会把数组里的每个元素都生成一个<source>节点,完美解决重复键的问题。
方法二:正确使用对象结构(避免报错)
你之前转对象报错,大概率是结构没弄对。正确的姿势是把source属性设置为一个包含多个source对象的索引数组,而不是给对象加多个source属性:
// 创建第一个source对象 $source1 = new stdClass(); $source1->name = 'somename1'; $source1->id = 'someid1'; // 创建第二个source对象 $source2 = new stdClass(); $source2->name = 'somename2'; $source2->id = 'someid2'; // 组装成完整的结构 $data = new stdClass(); $data->sources = new stdClass(); $data->sources->source = [$source1, $source2];
这样传给__soapCall就不会报“object has no 'name'/'source' property”的错了——之前的错误是因为你没有把重复的source放在一个数组里,SOAP扩展找不到对应的属性定义。
方法三:用SoapVar手动指定节点(极端情况)
如果上面两种方法都不好使(比如WSDL定义不明确,或者SOAP扩展自动解析有问题),可以用SoapVar手动控制每个节点的生成:
// 定义第一个source节点的SoapVar $source1 = new SoapVar( ['name' => 'somename1', 'id' => 'someid1'], SOAP_ENC_OBJECT, null, null, 'source' // 指定节点名称 ); // 定义第二个source节点的SoapVar $source2 = new SoapVar( ['name' => 'somename2', 'id' => 'someid2'], SOAP_ENC_OBJECT, null, null, 'source' ); // 组装成sources节点的SoapVar $sources = new SoapVar( [$source1, $source2], SOAP_ENC_OBJECT, null, null, 'sources' ); // 最终的调用数据 $data = ['sources' => $sources];
这个方法属于“硬核”手动编码,强制指定每个节点的名称和结构,适合那些SOAP扩展自动解析失效的场景。
小提示
如果你的SOAP服务有明确的WSDL文件,确保WSDL里<source>节点的maxOccurs属性设置为unbounded,这样SOAP扩展能更准确地解析你的数组/对象结构,减少踩坑概率。
内容的提问来源于stack exchange,提问作者Kevin

