PHP SOAP class 转换如何工作以及如何获得一致的列表结果?

How does PHP SOAP class transformation work and how do I get consistent list results?

所以我目前正在尝试使用 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>

可能return:

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

或:

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

我已将 someParamList 映射到 SomeParamListClass 和 someParam 到 SomeParamClass 使用 classmap 属性。这在一般情况下工作正常,但是 取决于结果我并不总是得到 SomeParamClassarray。如果列表中只有 1 个结果,PHP 将直接设置对象而不是包含单个对象的数组。

我尝试转换 __construct __set 或正常 setter 中的数据,但都没有被调用。

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

与各种反序列化例程一样,SoapClient 不会将值传递给构造函数或您可以拦截的 setter,它只是在内部创建对象并设置 "magically" 值。

您可以改为使用 typemap 选项而不是 classmap,它允许您为转换类型分配回调,而不是 class 名称。

但是,使用 $options 参数可以更轻松地绕过 "smart" 列表格式:

features option is a bitmask of ... 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
    ]
);