1 <sect1 id="zend.xmlrpc.server">
\r
2 <title>Zend_XmlRpc_Server</title>
\r
4 <sect2 id="zend.xmlrpc.server.introduction">
\r
8 Zend_XmlRpc_Server 依照 <ulink url="http://www.xmlrpc.com/spec">www.xmlrpc.com 上的规格描述</ulink>
\r
9 实现了一个全功能 XML-RPC 服务器。同时,它还实现了允许批量传输(boxcarring)的 system.multicall()
\r
14 <sect2 id="zend.xmlrpc.server.usage">
\r
21 <programlisting role="php"><![CDATA[<?php
\r
22 require_once 'Zend/XmlRpc/Server.php';
\r
23 require_once 'My/Service/Class.php';
\r
25 $server = new Zend_XmlRpc_Server();
\r
26 $server->setClass('My_Service_Class');
\r
27 echo $server->handle();]]>
\r
31 <sect2 id="zend.xmlrpc.server.structure">
\r
32 <title>服务器结构</title>
\r
35 Zend_XmlRpc_Server 是由各种不同组件组成,包括服务器自身用于接收请求或进行相应的组件,
\r
40 为了启动 Zend_XmlRpc_Server,开发人员必须通过 <code>setClass()</code>
\r
41 和 <code>addFunction()</code> 方法附加一个或者多个类或函数到服务器。
\r
45 完成附加操作后,则可以向 <code>Zend_XmlRpc_Server::handle()</code>
\r
46 传递 <code>Zend_XmlRpc_Request</code> 对象,如果没有提供它将实例化一个
\r
47 <code>Zend_XmlRpc_Request_Http</code> 对象用于从 <code>php://input</code>
\r
52 这时 <code>Zend_XmlRpc_Server::handle()</code> 将基于请求尝试调度合适的处理程序。
\r
53 它将返回基于 <code>Zend_XmlRpc_Response</code> 的对象或者 <code>Zend_XmlRpc_Server_Fault</code>
\r
54 对象。这些对象都有 <code>__toString()</code> 用来创建合法的,允许直接返回的 XML-RPC 的
\r
59 <sect2 id="zend.xmlrpc.server.conventions">
\r
62 Zend_XmlRpc_Server 允许开发人员附加函数和类方法作为 XML-RPC 方法来调度。通过
\r
63 Zend_Server_Reflection 自省所有附加的方法,使用函数和方法的文档部分(docblocks)
\r
68 XML-RPC 类型不可能与 PHP 类型一一对应。然而程序仍然利用 @param 和 @return
\r
69 的值列表尽可能的猜测最合适的类型。一些 XML-RPC 类型没有合适的 PHP 中的匹配,
\r
70 所以应当在 phpdoc 中对 XML-RPC 类型给予提示。这些包括:
\r
74 <listitem><para>dateTime.iso8601,字符串格式
\r
75 YYYYMMDDTHH:mm:ss</para></listitem>
\r
76 <listitem><para>base64, base64 编码数据</para></listitem>
\r
77 <listitem><para>struct, 结构匹配的数组</para></listitem>
\r
84 <programlisting role="php"><![CDATA[<?php
\r
88 * @param base64 $val1 Base64-encoded data
\r
89 * @param dateTime.iso8601 $val2 An ISO date
\r
90 * @param struct $val3 An associative array
\r
93 function myFunc($val1, $val2, $val3)
\r
99 PhpDocumentor 不会验证参数和返回值的类型,所以这对 API 文档没有任何影响。
\r
100 而且当服务器验证调用方法所提供的参数时,就必须提供提示。
\r
104 最有效的办法是未参数和返回值指定多个类型;XML-RPC 文档甚至建议 system.methodSignature
\r
105 应当返回一个数组,含有所有可能的方法标识(例如,参数和返回值的所有可能的组合)。
\r
106 你可以像通常那样在 PhpDocumentor 中使用“|”符号做到这点:
\r
109 <programlisting role="php"><![CDATA[<?php
\r
113 * @param string|base64 $val1 String or base64-encoded data
\r
114 * @param string|dateTime.iso8601 $val2 String or an ISO date
\r
115 * @param array|struct $val3 Normal indexed array or an associative array
\r
116 * @return boolean|struct
\r
118 function myFunc($val1, $val2, $val3)
\r
124 需要注意的是,允许多个标识可能干扰使用服务的开发人员;一般来说,一个 XML-RPC
\r
129 <sect2 id="zend.xmlrpc.server.namespaces">
\r
130 <title>使用命名空间</title>
\r
133 XML-RPC 有名字空间的概念;通常,它允许使用“.”分割 XML-RPC 方法到各个命名空间。
\r
134 这有助于防止不同类提供的不同服务方法之间的命名冲突。例如,XML-RPC
\r
135 服务在命名空间“system”中保留了一些方法:
\r
139 <listitem><para>system.listMethods</para></listitem>
\r
140 <listitem><para>system.methodHelp</para></listitem>
\r
141 <listitem><para>system.methodSignature</para></listitem>
\r
145 从内部来讲,这些方法映射到 Zend_XmlRpc_Server 的同名方法上。
\r
149 如果想要为服务方法增加命名空间,只要在附加一个函数或类时,添加命名空间到适当的方法上:
\r
152 <programlisting role="php"><![CDATA[<?php
\r
153 // My_Service_Class 类的公共方法将被映射为 myservice.METHODNAME
\r
154 $server->setClass('My_Service_Class', 'myservice');
\r
156 // 函数“somefunc”将被映射为 funcs.somefunc
\r
157 $server->addFunction('somefunc', 'funcs');]]>
\r
161 <sect2 id="zend.xmlrpc.server.request">
\r
162 <title>自定义请求对象</title>
\r
165 多数情况下,只需要使用 Zend_XmlRpc_Server 默认提供的请求类型
\r
166 Zend_XmlRpc_Request_Http。然而,仍然有可能在 CLI、GUI 或者其他环境使用
\r
167 XML-RPC,亦或需要记录每个请求。需要从 Zend_XmlRpc_Request
\r
168 继承,创建自定义的对象来完成这个工作。最重要的是记得确保实现 getMethod()
\r
169 和 getParams() 方法,这样 XML-RPC 服务器就可以获取必要的信息进行调度。
\r
173 <sect2 id="zend.xmlrpc.server.response">
\r
174 <title>自定义响应对象</title>
\r
177 和请求对象一样,Zend_XmlRpc_Server 可以返回自定义响应对象;默认情况下,
\r
178 Zend_XmlRpc_Response_Http 对象被返回,这个对象包含一个合适的用于 XML-RPC 的
\r
179 HTTP Content-Type 头。使用自定义对象的情况可能是需要记录响应,或需要发送响应到
\r
184 在调用 handle() 之前使用 Zend_XmlRpc_Server::setResponseClass()
\r
189 <sect2 id="zend.xmlrpc.server.fault">
\r
190 <title>处理错误产生的异常</title>
\r
193 Zend_XmlRpc_Server 会捕获调度方法产生的一场,同时生成 XML-RPC 失败响应。
\r
194 然而,默认情况下,异常消息和代码不出现在失败响应中。有意设计成如此形式主要是为了保护代码;
\r
195 许多异常会暴露超出预期的大量关于代码和开发环境的信息(常见的例子如数据库抽象层或访问层一场)。
\r
199 异常类也可以加入白名单中作为失败响应。要做到这点,只需使用
\r
200 Zend_XmlRpc_Server_Fault::attachFaultException() 添加一个异常类到白名单即可:
\r
203 <programlisting role="php"><![CDATA[<?php
\r
204 Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');]]>
\r
208 如果你使用的是一个继承于其他项目的异常,可以一次将整个类树加入白名单。
\r
209 Zend_XmlRpc_Server_Exceptions 总是在白名单中,用于报告指定的内部错误(如未定义的方法等)。
\r
213 一个未在白名单中指定的异常将会返回错误代码“404”,错误消息“Unknown error”(未知错误)。
\r
217 <sect2 id="zend.xmlrpc.server.caching">
\r
218 <title>在请求之间缓存服务器定义</title>
\r
220 附加多个类到 XML-RPC 服务器实例可能消耗大量的资源;每一个类必须使用反射
\r
221 API 进行自省(通过 Zend_Server_Reflection),生成一个包含有所有可用方法的列表用于服务器调用。
\r
224 为了减少这种性能污点,可以使用 Zend_XmlRpc_Server_Cache 来缓存请求之间的服务器定义。
\r
225 联合 __autoload() 使用,可以极大的提高性能。
\r
230 <programlisting role="php"><![CDATA[<?php
\r
231 require_once 'Zend/Loader.php';
\r
232 require_once 'Zend/XmlRpc/Server.php';
\r
233 require_once 'Zend/XmlRpc/Server/Cache.php';
\r
235 function __autoload($class)
\r
237 Zend_Loader::loadClass($class);
\r
240 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
\r
241 $server = new Zend_XmlRpc_Server();
\r
243 if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
\r
244 require_once 'My/Services/Glue.php';
\r
245 require_once 'My/Services/Paste.php';
\r
246 require_once 'My/Services/Tape.php';
\r
248 $server->setClass('My_Services_Glue', 'glue'); // glue. namespace
\r
249 $server->setClass('My_Services_Paste', 'paste'); // paste. namespace
\r
250 $server->setClass('My_Services_Tape', 'tape'); // tape. namespace
\r
252 Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
\r
255 echo $server->handle();]]>
\r
258 上面的例子尝试从当前脚本所在目录下的 xmlrpc.cache 文件获取服务器定义。
\r
259 如果失败的话就加载需要的服务类,附加他们到服务器实例,并尝试使用服务器定义创建新的缓存文件。
\r
263 <sect2 id="zend.xmlrpc.server.use">
\r
264 <title>使用实例</title>
\r
266 下面有一些有用的例子,向开发人员展示了可能用到的各种情况。
\r
267 每一个实例都是建立在前一个实例基础上的扩充。
\r
269 <sect3 id="zend.xmlrpc.server.use.case1">
\r
270 <title>基本使用</title>
\r
273 下面的例子演示了附加一个函数作为 XML-RPC 的调度方法,并用其处理请求。
\r
276 <programlisting role="php"><![CDATA[<?php
\r
277 require_once 'Zend/XmlRpc/Server.php';
\r
282 * @param string $value Value to md5sum
\r
283 * @return string MD5 sum of value
\r
285 function md5Value($value)
\r
287 return md5($value);
\r
290 $server = new Zend_XmlRpc_Server();
\r
291 $server->addFunction('md5Value');
\r
292 echo $server->handle();]]>
\r
296 <sect3 id="zend.xmlrpc.server.use.case2">
\r
297 <title>附加一个类</title>
\r
300 下面的例子演示了附加一个类的公共方法作为 XML-RPC 的调度方法。
\r
303 <programlisting role="php"><![CDATA[<?php
\r
304 require_once 'Zend/XmlRpc/Server.php';
\r
305 require_once 'Services/Comb.php';
\r
307 $server = new Zend_XmlRpc_Server();
\r
308 $server->setClass('Services_Comb');
\r
309 echo $server->handle();]]>
\r
313 <sect3 id="zend.xmlrpc.server.use.case3">
\r
314 <title>利用命名空间附加多个类</title>
\r
317 下面的例子演示了附加多个类,每个类都有自己的命名空间。
\r
320 <programlisting role="php"><![CDATA[<?php
\r
321 require_once 'Zend/XmlRpc/Server.php';
\r
322 require_once 'Services/Comb.php';
\r
323 require_once 'Services/Brush.php';
\r
324 require_once 'Services/Pick.php';
\r
326 $server = new Zend_XmlRpc_Server();
\r
327 $server->setClass('Services_Comb', 'comb'); // methods called as comb.*
\r
328 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
\r
329 $server->setClass('Services_Pick', 'pick'); // methods called as pick.*
\r
330 echo $server->handle();]]>
\r
334 <sect3 id="zend.xmlrpc.server.use.case4">
\r
335 <title>指定异常作为合法的失败响应</title>
\r
338 下面的例子允许任何 Services_Exception 的派生类作为失败响应返回其代码和消息。
\r
341 <programlisting role="php"><![CDATA[<?php
\r
342 require_once 'Zend/XmlRpc/Server.php';
\r
343 require_once 'Zend/XmlRpc/Server/Fault.php';
\r
344 require_once 'Services/Exception.php';
\r
345 require_once 'Services/Comb.php';
\r
346 require_once 'Services/Brush.php';
\r
347 require_once 'Services/Pick.php';
\r
349 // 允许 Services_Exceptions 作为响应失败输出
\r
350 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
\r
352 $server = new Zend_XmlRpc_Server();
\r
353 $server->setClass('Services_Comb', 'comb'); // methods called as comb.*
\r
354 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
\r
355 $server->setClass('Services_Pick', 'pick'); // methods called as pick.*
\r
356 echo $server->handle();]]>
\r
360 <sect3 id="zend.xmlrpc.server.use.case5">
\r
361 <title>设置自定义请求对象</title>
\r
364 下面的例子演示了实例化自定义请求对象并将其传递到服务器进行处理。
\r
367 <programlisting role="php"><![CDATA[<?php
\r
368 require_once 'Zend/XmlRpc/Server.php';
\r
369 require_once 'Zend/XmlRpc/Server/Fault.php';
\r
370 require_once 'Services/Request.php';
\r
371 require_once 'Services/Exception.php';
\r
372 require_once 'Services/Comb.php';
\r
373 require_once 'Services/Brush.php';
\r
374 require_once 'Services/Pick.php';
\r
376 // 允许 Services_Exceptions 作为响应失败输出
\r
377 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
\r
379 $server = new Zend_XmlRpc_Server();
\r
380 $server->setClass('Services_Comb', 'comb'); // methods called as comb.*
\r
381 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
\r
382 $server->setClass('Services_Pick', 'pick'); // methods called as pick.*
\r
385 $request = new Services_Request();
\r
387 echo $server->handle($request);]]>
\r
391 <sect3 id="zend.xmlrpc.server.use.case6">
\r
392 <title>设置自定义响应对象</title>
\r
395 下面的例子演示了指定自定义类作为响应返回。
\r
398 <programlisting role="php"><![CDATA[<?php
\r
399 require_once 'Zend/XmlRpc/Server.php';
\r
400 require_once 'Zend/XmlRpc/Server/Fault.php';
\r
401 require_once 'Services/Request.php';
\r
402 require_once 'Services/Response.php';
\r
403 require_once 'Services/Exception.php';
\r
404 require_once 'Services/Comb.php';
\r
405 require_once 'Services/Brush.php';
\r
406 require_once 'Services/Pick.php';
\r
408 // 允许 Services_Exceptions 作为响应失败输出
\r
409 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
\r
411 $server = new Zend_XmlRpc_Server();
\r
412 $server->setClass('Services_Comb', 'comb'); // methods called as comb.*
\r
413 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
\r
414 $server->setClass('Services_Pick', 'pick'); // methods called as pick.*
\r
417 $request = new Services_Request();
\r
420 $server->setResponseClass('Services_Response');
\r
422 echo $server->handle($request);]]>
\r
426 <sect3 id="zend.xmlrpc.server.use.case7">
\r
427 <title>在请求之间缓存服务器定义</title>
\r
430 下面的例子演示了在请求之间缓存服务器定义。
\r
433 <programlisting role="php"><![CDATA[<?php
\r
434 require_once 'Zend/XmlRpc/Server.php';
\r
435 require_once 'Zend/XmlRpc/Server/Fault.php';
\r
436 require_once 'Zend/XmlRpc/Server/Cache.php';
\r
437 require_once 'Services/Request.php';
\r
438 require_once 'Services/Response.php';
\r
439 require_once 'Services/Exception.php';
\r
440 require_once 'Services/Comb.php';
\r
441 require_once 'Services/Brush.php';
\r
442 require_once 'Services/Pick.php';
\r
445 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
\r
447 // 允许 Services_Exceptions 作为响应失败输出
\r
448 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
\r
450 $server = new Zend_XmlRpc_Server();
\r
453 if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
\r
454 $server->setClass('Services_Comb', 'comb'); // methods called as comb.*
\r
455 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
\r
456 $server->setClass('Services_Pick', 'pick'); // methods called as pick.*
\r
459 Zend_XmlRpc_Server_Cache::save($cacheFile, $server));
\r
463 $request = new Services_Request();
\r
466 $server->setResponseClass('Services_Response');
\r
468 echo $server->handle($request);]]>
\r
474 vim:se ts=4 sw=4 et:
\r