我在用SoapClient调用的响应进行PHP解析时遇到麻烦。对于某些类型的答案,它将返回空的stdClass对象的数组,而不是初始化的stdClass对象。
该服务器是Java Web服务,在Tomcat 6上与axis2一起部署。有问题的服务调用的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调用时,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解析响应的级别数是否存在已知限制?
我有类似的问题。我经历了您经历的每一次迭代。 fl幸,我通过更改PHP.INI文件或ini_set('soap.wsdl_cache', WSDL_CACHE_NONE);
禁用了“ 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);
希望这对您或其他碰巧遇到类似问题的人有所帮助。
您是否通过调试或打印出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对象时正在做什么。 More info on __getLastResponse()。
这似乎是PHP中的错误。 http://bugs.php.net/bug.php?id=49070
不幸的是,错误跟踪器不会让我对此发表评论。
我们将近一年半以后...
根据我最近的半类似经验,这不是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服务功能输出定义为上面的“良好”方式解决了我的问题。
要解决这个问题,您可以获取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);
所有数据都应该在$ responseObject中,甚至包括您之前看不到的数据。