将PHP SOAPClient对象序列化

4
我正在编写一个PHP应用程序,使用多个SOAP Web服务来收集数据。
在实例化所有这些对象时,我遇到了重大的开销:在某些情况下,一行代码$object = new SoapClient($wsdl);可能需要超过三秒钟。显然,只需要几个这样的操作就可以使网页感觉非常缓慢。
为了加快速度,我想把对象序列化并将它们存储在会话中(或类似地方),因此我编写了以下函数:
function soap_client($name,$wsdl) {
    if (!isset($_SESSION['soapobjects'][$name])) {
        $client = new SoapClient($wsdl, array('trace' => 1));
            $_SESSION['soapobjects'][$name]=serialize($client);
        } else {
            $client = unserialize($_SESSION['soapobjects'][$name]);
        }
    return $client;
}

看起来这确实是PHP推荐的做法

...然后像这样调用它...

$client = soap_client('servicename',$wsdl);
$client->MethodName($parameters);

然而,它似乎不起作用。 第一次运行时,它运行正常(即创建对象并制作序列化副本,方法调用正常)。但是第二次运行时,它失败了。 该对象看起来已正确序列化和反序列化,但当您尝试在反序列化的对象上执行SOAP调用时,它将抛出以下错误:
Fatal error: Uncaught SoapFault exception: [Client] Error finding "uri" property

很明显,反序列化的对象与原始对象不同,这与对象序列化的预期工作方式不符。

有人能解释一下我为什么会得到这个错误吗?你能建议一种使其正常工作的方法或者我可以追求的替代策略吗?

谢谢。

附言 - 我已经尝试绕过这个问题,但是没有成功。

我已经尝试在选项参数中指定URI(如PHP SOAP Client手册中所述),但是并没有什么区别。但是这也不应该必要,因为我正在使用WSDL。

我还尝试了简单地将对象复制到$_SESSION中,而不使用serialize()deserialize(),但是效果完全相同。

2个回答

3
内置的SOAP扩展是一个难以调试的二进制恐怖块。很可能它并不考虑序列化问题。例如,它可能包含一个内部文件句柄,在序列化/反序列化过程中无法存活。我建议您使用其他SOAP客户端,例如:
  • Zend_Soap,是Zend Framework的一部分。您不需要在代码的任何其他区域使用该框架,并且可能可以删除大多数其他组件。但是,它似乎在底层使用现有的SOAP扩展,因此可能不适合进行序列化。
  • PEAR's SOAP经常被引用,但已经有些陈旧了。
  • NuSOAP最近被重新启动,但所有在线文档似乎都消失在zip文件中。

如果这些都不适合,请考虑将WSDL文件缓存在本地,因为我认为延迟可能就在那里。


谢谢回复。我进行了进一步的调查,看起来你的分析是正确的——序列化字符串对于重建对象几乎没有用处;它几乎什么都没有,所以反序列化它不起作用也就不足为奇了。我会研究其他替代方案,但 PHP SOAP 已经很好地融入了我们的应用程序,所以可能切换会带来太多麻烦。我们已经研究过 WSDL 缓存;到目前为止还没有成功,但我会重新访问它,因为我认为之前我们做错了些什么。 - Spudley
不建议学习另一个 SOAP 扩展,我建议研究一下 WSDL 缓存。当然,除非你追求某个特定的功能。 - denormalizer
2
@Charles 使用Zend_Soap_Client也不起作用,因为它包装了一个扩展的SoapClient类。将其存储到(Zend_)缓存或(Zend_)会话中也会导致反序列化问题,除非您之前没有使用过该客户端。由于Zend_Soap_Client懒加载底层SoapClient,这可能会导致应用程序出现意外的副作用。 - Partyschaum
谢谢,@Partyschaum,我已经将那些信息整合到我的答案中了。 - Charles

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接