SOAP structures in PHP

Danne on October 31st, 2008

Handling SOAP structures in PHP can sometimes be really annoying. If an interface is defined in the WSDL as returning an array I can’t be sure that I will get an array. If there is only one element in the array PHP tries to be clever and turn the wanted array into an object which, too me, isn’t really smart. I don’t know if this is a problem/limitation on the client side, server side or if it is just me doing something stupid in the wsdl.

As an example I have the below complex types, message and operation defined in the WSDL file. (The example is not complete of course.)

    <complexType name="KeyValueData">
      <sequence>
        <element minOccurs="1" maxOccurs="1" name="id" type="string"/>
        <element minOccurs="1" maxOccurs="1" name="name" type="string"/>
        <element minOccurs="1" maxOccurs="1" name="data" type="string"/>
      </sequence>
    </complexType>

    <complexType name="ArrayOfKeyValueData">
      <sequence>
        <element minOccurs="0" maxOccurs="unbounded"
                 name="keyval" type="tns:KeyValueData"/>
      </sequence>
    </complexType>
      ...
    <message name="StatisticsListOutput">
      <part name="data" element="tns:ArrayOfKeyValueData"/>
    </message>
      ...
    <operation name="getStatistics">
      <input message="tns:StatisticsListInput"/>
      <output message="tns:StatisticsListOutput"/>
    </operation>

Sending this from the client is an absolute no brainer. It is a simple array containg associative arrays in every slot. When receiving this structure on the client side the original array (the member variable Map in the example) with one element turns into

Class Object
(
    [Map] => stdClass Object
        (
            [item] => Array
                (
                    [0] => stdClass Object
                        (
                            [key] => id
                            [value] => value
                        )

                    [1] => stdClass Object
                        (
                            [key] => name
                            [value] => value
                        )

where an array with multiple elements turn into

stdClass Object
(
    [Map] => Array
        (
            [0] => stdClass Object
                (
                    [item] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [key] => id
                                    [value] => value
                                )

                            [1] => stdClass Object
                                (
                                    [key] => name
                                    [value] => value
                                )

This is annoying. Just imagine the situation when you have multiple arrays in arrays… Which actually does happen every once in a while when sending compounds of various elements declared as ComplexTypes in the WSDL.

Is it a feature, quirk or anti social behaviour? I don’t know. If there is another way I’d like to hear about it.

Tags: , , ,

13 Responses to “SOAP structures in PHP”

  1. Quite annoying indeed.

    But the fault lies in xml being a child of sgml: it was not designed for storing data, but rather for storing documents.
    Just think at how much money has globally been lost in the world in time spent thinking whether some piece of data was to be coded as an element attribute or a sub-element…
    And xsd is the most unnecessarily bloated and complex xml definition language that could be bolted on top of it. Quite an unlucky combination for the SOAP guys.

    If you want to keep mental sanity and decent execution speed, go for json or xmlrpc.

  2. It’s considered a feature. Create your soap client object like this:

    $soap = new SoapClient(
        $wsdlurl,
        array('features' =&gt; SOAP_SINGLE_ELEMENT_ARRAYS));

    See also the comment in: http://no2.php.net/manual/en/f.....struct.php

  3. gaetano

    That would be nice to force third party data providers to use JSON, but reality is that there are a bunch of lovely folks out there who think SOAP should work as advertised.

    I have to agree with Danne. We deal with a couple shops that love their complex data types. They hand coded their WSDLs taking full advantage of them. When we come across these sorts of things, PHP falls flat on it’s face.

    If I could motivate anyone in the internals, I would say: who cares about PHP6, give me a fully WSDL compatible SOAP extension and a comprehensive solution for complex data types.

    There are a couple PHP coded projects out there that try to make up for the shortcomings, but those things should be native and predictable. I think it is ironic that PHP’s weakest point right now is SOAP.

  4. It’s considered a feature. But there’s a way to make it work better. There’s an option when creating the SOAP object called SOAP_SINGLE_ELEMENT_ARRAYS. You can google or search the PHP documentation for it.

  5. Not sure if this will come thru in the comment, but here is a slightly different WSDL construction that I am fairly sure will facilitate always returning an array, even if the data structure encoded in it has 1 element.

     

    The corresponding PHP server code to create the response would be something like

    new SoapVar($arrayOfKeyValueData, SOAP_ENC_ARRAY, "ArrayOfKeyValueData", "[your target namespace]“);

  6. Uh… strike 1. try again…

  7. strike 2… almost done. last try…

    <complexType name="ArrayOfKeyValueData">
    <complexContent>
    <restriction base="SOAP-ENC:Array">
    <attribute ref="SOAP-ENC:arrayType"
    wsdl:arrayType="tns:KeyValueData[]” />
    </restriction>
    </complexContent>
    </complexType&grt;

  8. http://bugs.php.net/bug.php?id=36226 says:
    $x = new SoapClient($wsdl, array('features' =>
    SOAP_SINGLE_ELEMENT_ARRAYS));

  9. Havr you tried the following:


    $x = new SoapClient($wsdl, array('features' =>
    SOAP_SINGLE_ELEMENT_ARRAYS));

    Not sure if this is documented in the manual though.

  10. What about the issue of if you are building your WSDLs this way, using WS-I compliant arrays, you can’t properly pass or retrieve arrays without everything wrapping in stdClass objects?

    However, if he built the exact same WSDL using soap-enc:Array, this all would have returned the results in a nice package of:

    array(
    array(
    ‘id’ => xxx, ‘name’ => yyy, ‘data’ => zzz),
    array(
    ‘id’ => aaa, ‘name’ => bbb, ‘data’ => ccc));

    I have yet to find a solution for this WS-I soapenc:Array issue.

Trackbacks/Pingbacks

  1. Danne Lundqvist’s Blog: SOAP structures in PHP : Dragonfly Networks
  2. Danne Lundqvist’s Blog: SOAP structures in PHP : WebNetiques
  3. PHP SOAP Structures Discussion « Mcloide’s resources library

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="">