4

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

服务器是一个java webservice,用axis2部署在tomcat6上。有问题的服务调用的 Java 签名是public Course getCourseDetails(Long courseId) Course 是一个标准的 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 :

<?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

6 回答 6

4

我有一个类似的问题。我经历了你经历的每一次迭代。ini_set('soap.wsdl_cache', WSDL_CACHE_NONE);幸运的是,我通过更改 PHP.INI 文件或在我的下一个请求中填充了所有丢失的数据来禁用缓存“soap.wsdl_cache” 。这很容易发生,因为“soap.wsdl_cache_ttl”默认设置为“86400”,即 60 天。

我发现肥皂服务器发生了代码更改。创建一个新的 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);

希望这可以帮助您或其他任何碰巧路过并遇到类似问题的人。

于 2011-05-05T17:59:59.890 回答
1

您是否通过调试或打印出 PHP 对象(print_r、var_dump)的内容来解决所有这些问题?

您是否尝试过打印出实际的 SOAP 响应字符串(不是 PHP 对象)?您可以通过创建带有调试选项集的 SoapClient 来做到这一点:

$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();

这可以帮助您弄清楚 SoapClient 在将响应转换为 PHP 对象时在做什么。有关 __getLastResponse() 的更多信息

于 2009-12-02T05:44:37.167 回答
0

这似乎是 PHP 中的一个错误。 http://bugs.php.net/bug.php?id=49070

不幸的是,错误跟踪器不允许我对此发表评论。

于 2010-01-04T20:13:20.993 回答
0

将近一年半后我们去...

在我最近的半相似经验中,这不是 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 服务功能输出定义为上述“好”方式解决了我的问题。

于 2011-03-23T18:32:30.247 回答
0

为了解决这个问题,您可以获取肥皂响应的 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);

所有的数据都应该在 $responseObject 中,即使是你以前看不到的数据。

于 2019-10-18T08:26:39.327 回答
0

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

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

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

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

于 2020-03-09T10:45:47.393 回答