Roc*_*mat 14 php soap soap-client
我正在使用PHP的SOAPClient类与SOAP API进行通信.其中一个选项允许您使用自己的类重新映射WSDL文件中指定的类型:
将类映射选项可用于一些WSDL类型映射到PHP类.此选项必须是一个数组,其中WSDL类型作为键,PHP类的名称作为值.
我这样创建我的客户端:
$api = new SOAPClient('http://example.com/soap.wsdl', [
'location' => 'http://example.com/soap/endpoint',
'soap_version' => SOAP_1_2,
'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
'cache_wsdl' => WSDL_CACHE_BOTH,
'classmap' => [
'APIResultObject' => 'Result'
],
# TODO: Set for debug only?
'trace' => TRUE,
'exceptions' => TRUE
]);
Run Code Online (Sandbox Code Playgroud)
这是有效的,当我调用时$api->method('param'),我得到一个Result对象(而不仅仅是一个StdClass对象).问题是Result::__construct()永远不会调用该方法,因此Result永远不会设置某些私有属性.
这是什么Result:
class DataClass{
protected $data;
function __construct(){
$this->data = ['a' => 0, 'b' => 1, 'c' => 2];
}
}
class Result extends DataClass{
public $value, $name, $quantity;
function __construct(array $values){
parent::__construct();
foreach(['value', 'name', 'quantity'] as $var){
$this->$var = isset($values[$var]) ? $values[$var] : NULL;
}
}
function getData(){
return $this->data[$this->name];
}
}
Run Code Online (Sandbox Code Playgroud)
发生了什么事我正在做$api->method('param')->getData()并收到以下错误:
注意:未定义的属性:Result :: $ data
如何在获取SOAP响应时调用我需要的构造函数?我尝试过使用__wakeup(),但这似乎也没有用.
PS我用一个小的解决方法"解决"了它,但我不认为这是理想的.这是我做的:
function getData(){
if($this->data === NULL){
parent::__construct();
}
return $this->data[$this->name];
}
Run Code Online (Sandbox Code Playgroud)
您可以将SoapClient包装在另一个将正确调用构造函数的类中.为了省事,班级会检查是否需要.仍然不理想,但我认为这种方式更简单.
class ActiveSOAPClient extends SoapClient {
// Intercept all calls to class.
public function __call($func, $params) {
// Pass it to parent class.
$ret = parent::__call($func, $params);
// If the answer is an object...
if (is_object($ret)
// Taboo functions that will pass unhindered.
// && (!in_array($func, [ ARRAY OF EXCLUDED_FUNCTIONS ]))
) {
// ...and the object is in the auto classmap...
if (false !== array_search(get_class($ret), $this->_classmap, true)) {
// ...then assume it's an incomplete object and try activating it.
$ret->__construct();
}
}
return $ret;
}
}
Run Code Online (Sandbox Code Playgroud)
优点是ActiveSOAPClient该类不需要有关于您自己的逻辑的任何信息,并且您的逻辑不需要更改.
我认为这种行为是故意的或已知的错误(即,必须有一些原因或问题),因为在手册页中它已经在七年前就被注意到了.
我查看了PHP 5.5.6的源代码.至于我可以读取php_encoding.c中的代码,
/* Struct encode/decode */
static zval *to_zval_object_ex(encodeTypePtr type, xmlNodePtr data, zend_class_entry *pce TSRMLS_DC)
{
zval *ret;
xmlNodePtr trav;
sdlPtr sdl;
sdlTypePtr sdlType = type->sdl_type;
zend_class_entry *ce = ZEND_STANDARD_CLASS_DEF_PTR;
zval *redo_any = NULL;
if (pce) {
ce = pce;
} else if (SOAP_GLOBAL(class_map) && type->type_str) {
zval **classname;
zend_class_entry *tmp;
if (zend_hash_find(SOAP_GLOBAL(class_map), type->type_str, strlen(type->type_str)+1, (void**)&classname) == SUCCESS &&
Z_TYPE_PP(classname) == IS_STRING &&
(tmp = zend_fetch_class(Z_STRVAL_PP(classname), Z_STRLEN_PP(classname), ZEND_FETCH_CLASS_AUTO TSRMLS_CC)) != NULL) {
ce = tmp;
}
}
Run Code Online (Sandbox Code Playgroud)
...如果定义了类映射,并且已知,则调用zend_fetch_class().
我认为应该在从节点获取的值之后调用某种ctor()函数,例如在PDO :: fetchObject中完成(参见文件"ext/pdo/pdo_stmt.c").
目前,似乎没有这样做.可能是因为XML树中对象的评估顺序,这使得为构造函数提供适当的参数很棘手,但此时我只是在猜测.
但是,你当时没有"官方"的解决方案是正确的(你不能获得比源代码更多的官方解决方案).
我试图在PHP源代码中添加一个构造函数运行器,只是为了它的地狱.不幸的是,我似乎需要几个不在我需要的范围内的变量,所以我必须改变几个结构来传递构造函数信息等等,这些结构在SOAP代码中普遍使用.
除了最简单的情况下,对象具有无参数构造函数且没有析构函数,对代码的必要修改对我来说根本不是轻微的.
这是已知行为(错误报告)。
正如有人在错误报告中建议的那样(miceleparkip at web dot de):
这不是一个错误。这很正常。
肥皂对象是在服务器端创建的。所以构造函数只是在服务器上调用。
我同意她的立场。
同一个错误报告中的后续评论(php at hotblocks dot nl )不同意:
服务器不创建对象,而是发送 XML。客户端对该 XML 进行解码并创建对象。
虽然从技术角度来看这是无可争议的事实,但“抽象”对象可以说是在服务器端创建的。是否先转换为 XML,然后在客户端进行重构,这是应用层不需要关心的低级问题。
如果您的应用程序需要比服务器提供的功能更多的对象,我将创建一个本地类,它将创建的对象作为SOAPClient构造函数参数:
class MySoapResultClass {
// whatever
}
class LocalApplicationClass {
public function __construct(MySoapResultClass $soapResult) {
// your local initialization code
$this->data = ['a' => 0, 'b' => 1, 'c' => 2];
// then either extract your data from $soapResult,
// or just store a reference to it
}
public function getData(){
return $this->data[$this->name];
}
}
$api = new SOAPClient(...);
$soapResult = $api->method('param');
$myUsefulObject = new LocalApplicationClass($soapResult);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1727 次 |
| 最近记录: |