代码之家  ›  专栏  ›  技术社区  ›  Ryan Ahearn

PHP SoapClient调用响应缺少部分答案

  •  3
  • Ryan Ahearn  · 技术社区  · 15 年前

    我在PHP解析SoapClient调用的响应时遇到问题。对于某些类型的回答,它返回空stdClass对象的数组,而不是初始化的stdClass对象。

    该服务器是一个java Web服务,与tomcat6上的axis2一起部署。有问题的服务调用的Java签名是 public Course getCourseDetails(Long courseId) 课程是标准的POJO,定义如下:

    public class Course {
        private Long id;
        private List<Hole> holes;
        private String name;
        private String tees;
    
        //etc...
    }
    

    Hole是一个标准的POJO,只有灵长类成员。

    使用PHP调用时,holes成员是一个长度正确的数组,但每个hole都是空的。

    $args = array();
    $args["courseId"] = $courseId;
    $response = $client->getCourseDetails($args);
    $course = $response->return;
    //course has all of its primitive members set correctly: good
    $holes = $course->holes;
    //holes is an array with count = 18: good
    $hole = $holes[0];
    //hole is an empty stdClass: bad
    

    使用 $soapClient->__getLastResponse()

    <?xml version='1.0' encoding='utf-8'?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
    <ns:getCourseDetailsResponse xmlns:ns="http://webservice.golfstats">
    <ns:return xmlns:ax21="http://datastructures.server.golfstats/xsd" xmlns:ax22="http://util.java/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ax24="http://uuid.eaio.com/xsd" xsi:type="ax21:Course">
    <ax21:courseLocation>Faketown, VA</ax21:courseLocation>
    <ax21:courseName>Fake Links</ax21:courseName>
    <ax21:dateAdded>2003-01-02</ax21:dateAdded>
    <ax21:holes><ax21:id>1</ax21:id><ax21:number>1</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>2</ax21:id><ax21:number>2</ax21:number><ax21:par>3</ax21:par><ax21:yardage>150</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>3</ax21:id><ax21:number>3</ax21:number><ax21:par>5</ax21:par><ax21:yardage>502</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>4</ax21:id><ax21:number>4</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>5</ax21:id><ax21:number>5</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>6</ax21:id><ax21:number>6</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>7</ax21:id><ax21:number>7</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>8</ax21:id><ax21:number>8</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>9</ax21:id><ax21:number>9</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>10</ax21:id><ax21:number>10</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>11</ax21:id><ax21:number>11</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>12</ax21:id><ax21:number>12</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>13</ax21:id><ax21:number>13</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>14</ax21:id><ax21:number>14</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>15</ax21:id><ax21:number>15</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>16</ax21:id><ax21:number>16</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>17</ax21:id><ax21:number>17</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:holes><ax21:id>18</ax21:id><ax21:number>18</ax21:number><ax21:par>4</ax21:par><ax21:yardage>345</ax21:yardage></ax21:holes>
    <ax21:id>1</ax21:id>
    <ax21:rating>68.5</ax21:rating>
    <ax21:slope>113</ax21:slope>
    <ax21:tees>Blue</ax21:tees>
    </ns:return>
    </ns:getCourseDetailsResponse>
    </soapenv:Body>
    </soapenv:Envelope>
    

    为什么每个洞都是空的stdClass?SoapClient解析响应的级别数是否存在已知限制?

    4 回复  |  直到 15 年前
        1
  •  4
  •   Brant Messenger    13 年前

    我也有类似的问题。我经历了你经历的每一次迭代。侥幸的是,我通过更改PHP.INI文件或 ini_set('soap.wsdl_cache', WSDL_CACHE_NONE); 在我的下一个请求中,所有缺失的数据都被填充了。这很容易发生,因为“soap.wsdl\u cache\u ttl”默认设置为“86400”,即60天。

    我发现soap服务器的代码发生了变化。创建新的wsdl。客户机的缓存wsdl在此时已过时。您可能认为,至少在每个请求中都会出现某种校验和散列,以验证wsdl是否已更改,但它没有更改。

    为了解决这个问题并仍然使用缓存,我创建了一个可以在本地使用的wsdl文件。

        $cache = Services_Utilities::getCacheResource();
        if (!$cache->test(self::CACHE_KEY)) {
            $data = file_get_contents($wsdl);
            $cache->save($data, self::CACHE_KEY);
            file_put_contents($newWsdl, $data);
            if (file_exists($newWsdl)) {
                $wsdl = $newWsdl;
            }
        } else {
            if (file_exists($newWsdl)) {
                $wsdl = $newWsdl;
            }
        }
    
        // Remove $newWsdl when necessary
        // unset($newWsdl);
    

    希望这能帮助你或其他碰巧路过并遇到类似问题的人。

        2
  •  1
  •   Chris Williams    15 年前

    您是否通过调试或打印PHP对象的内容(print\u r、var\u dump)解决了这些问题?

    $soapClient = new SoapClient( "http://your.soap.server.com/services/yourWsdl.wsdl", array("trace" => 1));
    

    然后,当您使用客户机进行SOAP调用时,您可以查看请求和响应字符串。

    $response = $soapClient->getCourseDetails($params);
    $requestAsString = $soapClient->__getLastRequest();
    $responseAsString = $soapClient->__getLastResponse();
    

    More info on __getLastResponse() .

        3
  •  0
  •   Ryan Ahearn    15 年前

    http://bugs.php.net/bug.php?id=49070

    不幸的是,bug追踪者不让我对此发表评论。

        4
  •  0
  •   Luke H    13 年前

    差不多一年半后我们就开始了。。。

    在我最近的类似经历中,这不是一个php错误。这是一个与Web服务的编写方式以及PHP如何读取输出相关的问题。我遇到了一个类似的问题(甚至是getLastResponse返回正确的XML),我发现并不是PHP或我的SOAP函数有问题,而是“断开”函数的结果不是显式定义的游标。

    PROCEDURE GetBlahByBlahID(IN IN_BLAH_ID VARCHAR, IN IN_BLAHPKG VARCHAR,                                     
    OUT result CURSOR
    ) BEGIN ...
    

    PROCEDURE GetBlahByBlahID(IN IN_BLAH_ID VARCHAR, IN IN_BLAHPKG VARCHAR,                                     
    OUT result CURSOR (  BLAH VARCHAR(250),
                         BLAH2 VARCHAR(250),
                         BLAH_DATE DATE,
                         BLAH3 VARCHAR(250))) BEGIN ...
    

    显然,Java可以很好地处理“坏的”/非显式输出,但PHP返回一个空对象数组。

    不确定这是否会对您有所帮助,但将web服务函数输出定义为上面提到的“好”方法解决了我的问题。

        5
  •  0
  •   Robin Brackez    5 年前

    要解决这个问题,可以获取soap响应的xml字符串并将其转换为对象。

    $soapClient = new \SoapClient($wsdl, ['trace' => 1]); // trace is essential to get the lastResponse string
    $soapClient->__call($function_name, $arguments);
    $soapResponse = $soapClient->__getLastResponse();
    $filteredSoapResponse = str_ireplace("soap:", "", $soapResponse); // remove the "soap:" namespace
    $responseObject = simplexml_load_string($filteredSoapResponse);
    

        6
  •  0
  •   ChrAesch    4 年前

    对我来说,问题是模式定义中缺少一个字段。

    <xsd:import schemaLocation="https://*****.svc?xsd=xsd2" namespace="http://FunctionName"/>
    

    数据传输正确,但PHP只显示远程模式中列出的字段。

    所以我不得不重新创建服务模式。