PHP SOAP类转换如何工作,如何获得一致的列表结果?

时间:2018-10-01 10:17:45

标签: php soap soap-client

所以我目前正在尝试使用PHP SoapClient来实现外部API调用-我发现它以一种非常奇怪的方式工作。

假设我有以下WSDL定义:

<xs:element name="someParamList">
  <xs:complexType>
    <xs:sequence>
      <xs:element maxOccurs="unbounded" minOccurs="0" name="someParam" type="someParam"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

哪个可能返回:

<someParamList>
  <someParam>foo</someParam>
  <someParam>bar</someParam>
</someParamList>

或:

<someParamList>
  <someParam>foo</someParam>
</someParamList>

我已将someParamList映射到SomeParamListClass 和使用SomeParamClass属性的classmap的someParam。一般来说,此方法效果很好,但但是取决于结果,我并非总是能得到array中的SomeParamClass。如果列表中只有1个结果,则PHP将直接设置对象,而不是其中包含单个对象的数组。

我尝试用__construct __set或普通的setter来转换数据,但是没有一个被调用。

所以: 为什么SoapClient的行为如此怪异,为什么它从不调用构造函数或setter? 以及如何获得一致的列表?

1 个答案:

答案 0 :(得分:1)

与各种反序列化例程一样,SoapClient不会将值传递给您可以拦截的构造函数或设置器,它只是在内部创建了具有“神奇”设置值的对象。

相反,您可以使用typemap选项而不是classmap,它使您可以分配用于转换类型而不是类名的回调。

但是,使用$options参数可以更轻松地绕过“智能”列表格式:

  

features选项是... SOAP_SINGLE_ELEMENT_ARRAYS ...的位掩码...

这在任何地方都没有真正描述,但是它迫使解码后的XML的每一个元素都是一个数组,而不是试图猜测哪个是单个的,哪个是多个的。这可能意味着您必须写很多$response[0]['foo'][0]['bar'][0],但至少可以预见。

所以:

$client = new SoapClient(
    $wsdl,
    [
        // other options which you're already passing here...
        'features' => SOAP_SINGLE_ELEMENT_ARRAYS
    ]
);