Zend_XmlRpc_Client.xml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. <sect1 id="zend.xmlrpc.client">
  2. <title>Zend_XmlRpc_Client</title>
  3. <sect2 id="zend.xmlrpc.client.introduction">
  4. <title>介绍</title>
  5. <para>
  6. Zend Framework 通过 <code>Zend_XmlRpc_Client</code> 作为客户端提供了调用远程
  7. XML-RPC 服务的功能。主要功能包括在 PHP 和 XML-RPC 之间进行类型的自动转换,
  8. 服务代理对象(a server proxy object),和访问服务器的自省功能
  9. (introspection capabilities)。
  10. </para>
  11. </sect2>
  12. <sect2 id="zend.xmlrpc.client.method-calls">
  13. <title>方法调用</title>
  14. <para>
  15. <code>Zend_XmlRpc_Client</code> 的构造函数接受 XML-RPC 服务器端 URL
  16. 地址作为第一个参数。返回新的实例可以用来调用这个服务器端任意数量的远程方法。
  17. </para>
  18. <para>
  19. 使用 XML-RPC 客户端调用远程方法,需要实例化它并且使用 <code>call()</code>
  20. 实力方法。下面的代码演示了调用 Zend Framework 网站上的 XML-RPC 服务。
  21. 你可以使用它测试和学习 <code>Zend_XmlRpc</code> 组件。
  22. </para>
  23. <example id="zend.xmlrpc.client.method-calls.example-1">
  24. <title>XML-RPC 方法调用</title>
  25. <programlisting role="php"><![CDATA[
  26. require_once 'Zend/XmlRpc/Client.php';
  27. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  28. echo $client->call('test.sayHello');
  29. // hello
  30. ]]>
  31. </programlisting>
  32. </example>
  33. <para>
  34. 从远程调用返回的 XML-RPC 值将会自动编排和转换为等价的 PHP 原始类型。
  35. 在上面的例子中,一个 PHP <code>string</code> 会返回并即刻可以使用。
  36. </para>
  37. <para>
  38. <code>call()</code> 方法接受远程调用的名字作为第一个参数。如果远程调用需要其他参数,
  39. 可以通过 <code>call()</code> 的第二个可选参数使用 <code>array</code>
  40. 的形式传递到远程方法。
  41. </para>
  42. <example id="zend.xmlrpc.client.method-calls.example-2">
  43. <title>XML-RPC 带参数的方法调用</title>
  44. <programlisting role="php"><![CDATA[
  45. require_once 'Zend/XmlRpc/Client.php';
  46. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  47. $arg1 = 1.1;
  48. $arg2 = 'foo';
  49. $result = $client->call('test.sayHello', array($arg1, $arg2));
  50. // $result is a native PHP type
  51. ]]>
  52. </programlisting>
  53. </example>
  54. <para>
  55. 如果远程方法不需要任何参数,这个可选参数可以留空或者传递一个空的 <code>array()</code>
  56. 过去。远程方法的参数数组可以包含原始的 PHP 类型,<code>Zend_XmlRpc_Value</code>
  57. 对象,或者两种的混合。
  58. </para>
  59. <para>
  60. <code>call()</code> 方法会自动转换 XML-PRC 响应并返回等价的 PHP 原始类型。
  61. 返回值的 <code>Zend_XmlRpc_Response</code> 对象也可以在调用之后使用
  62. <code>getLastResponse()</code> 方法获得。
  63. </para>
  64. </sect2>
  65. <sect2 id="zend.xmlrpc.value.parameters">
  66. <title>类型及转换</title>
  67. <para>
  68. 一些远程方法调用时需要参数。它们作为数组传递到 <code>Zend_XmlRpc_Client</code>
  69. 的 <code>call()</code> 方法的第二个参数。每个参数,不论是原始的 PHP 类型,
  70. 还是一个对象表示的特定的 XML-RPC 类型(一个 <code>Zend_XmlRpc_Value</code>
  71. 对象)都会自动转换。
  72. </para>
  73. <sect3 id="zend.xmlrpc.value.parameters.php-native">
  74. <title>PHP 原始类型作为参数</title>
  75. <para>
  76. 原始 PHP 变量如 <code>string</code>,<code>integer</code>,
  77. <code>float</code>,<code>boolean</code>,<code>array</code> 或者
  78. <code>object</code> 都可以作为参数传递到 <code>call()</code>。
  79. 在这种情况下,每个 PHP 原始类型将会自动检测和转换到一个 XML-RPC 类型,
  80. 如下表所示:
  81. </para>
  82. <table id="zend.xmlrpc.value.parameters.php-native.table-1">
  83. <title>PHP 与 XML-RPC 的类型转换</title>
  84. <tgroup cols="2">
  85. <thead>
  86. <row>
  87. <entry>PHP 原始类型</entry>
  88. <entry>XML-RPC 类型</entry>
  89. </row>
  90. </thead>
  91. <tbody>
  92. <row>
  93. <entry>integer</entry>
  94. <entry>int</entry>
  95. </row>
  96. <row>
  97. <entry>double</entry>
  98. <entry>double</entry>
  99. </row>
  100. <row>
  101. <entry>boolean</entry>
  102. <entry>boolean</entry>
  103. </row>
  104. <row>
  105. <entry>string</entry>
  106. <entry>string</entry>
  107. </row>
  108. <row>
  109. <entry>array</entry>
  110. <entry>array</entry>
  111. </row>
  112. <row>
  113. <entry>associative array</entry>
  114. <entry>struct</entry>
  115. </row>
  116. <row>
  117. <entry>object</entry>
  118. <entry>array</entry>
  119. </row>
  120. </tbody>
  121. </tgroup>
  122. </table>
  123. <note>
  124. <title>一个空的数组会如何转换?</title>
  125. <para>
  126. 传递空数组到 XML-RPC 方法,由于它既可表示为一个数组也可表示为一个结构,
  127. 所以会产生问题。<code>Zend_XmlRpc_Client</code> 会监测这种情况并向服务器进行一个
  128. <code>system.methodSignature</code> 请求来决定实际将要转换到的 XML-RPC 类型。
  129. </para>
  130. <para>
  131. 不过,这样做本身就可能导致问题出现。首先,服务器不支持 <code>system.methodSignature</code>
  132. 将会产生一个失败请求,同时 <code>Zend_XmlRpc_Client</code>
  133. 会强制转换这个值为 XML-RPC 数组类型。此外,这意味着任何数组参数都可能导致对远端服务器的一次额外请求。
  134. </para>
  135. <para>
  136. 可以在 XML-RPC 调用前调用 <code>setSkipSystemLookup()</code>
  137. 方法,以便完全屏蔽这个查询:
  138. </para>
  139. <programlisting role="php"><![CDATA[
  140. $client->setSkipSystemLookup(true);
  141. $result = $client->call('foo.bar', array(array()));
  142. ]]>
  143. </programlisting>
  144. </note>
  145. </sect3>
  146. <sect3 id="zend.xmlrpc.value.parameters.xmlrpc-value">
  147. <title><code>Zend_XmlRpc_Value</code> 对象作为参数</title>
  148. <para>
  149. 也可以创建 <code>Zend_XmlRpc_Value</code> 实例作为参数,以表示特定的
  150. XML-RPC 类型。这样做的主要原因如下:
  151. <itemizedlist>
  152. <listitem>
  153. <para>
  154. 当希望确定的参数类型被传递传递时(例如,方法需要一个整型,
  155. 而可能从数据库获得的是一个字符串)。
  156. </para>
  157. </listitem>
  158. <listitem>
  159. <para>
  160. 当方法需要 <code>base64</code> 或者 <code>dateTime.iso8601</code>
  161. 类型时(这些在 PHP 原始类型中不存在)。
  162. </para>
  163. </listitem>
  164. <listitem>
  165. <para>
  166. 当自动转换失败时(例如,你希望传递一个空的 XML-RPC
  167. 结构作为参数。空的结构在 PHP 中应当是一个空的数组,
  168. 但是如果传递一个空数组作为参数,它将被自动转换为 XML-RPC
  169. 数组,虽然它同数组没有联系)。
  170. </para>
  171. </listitem>
  172. </itemizedlist>
  173. </para>
  174. <para>
  175. 有两种方法创建 <code>Zend_XmlRpc_Value</code> 对象:直接实例化某个
  176. <code>Zend_XmlRpc_Value</code> 的子类;或者使用静态工厂方法
  177. <code>Zend_XmlRpc_Value::getXmlRpcValue()</code>。
  178. </para>
  179. <table id="zend.xmlrpc.value.parameters.xmlrpc-value.table-1">
  180. <title><code>Zend_XmlRpc_Value</code> 对象作为 XML-RPC 类型</title>
  181. <tgroup cols="3">
  182. <thead>
  183. <row>
  184. <entry>XML-RPC 类型</entry>
  185. <entry><code>Zend_XmlRpc_Value</code> 常量</entry>
  186. <entry><code>Zend_XmlRpc_Value</code> 对象</entry>
  187. </row>
  188. </thead>
  189. <tbody>
  190. <row>
  191. <entry>int</entry>
  192. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER</code></entry>
  193. <entry><code>Zend_XmlRpc_Value_Integer</code></entry>
  194. </row>
  195. <row>
  196. <entry>double</entry>
  197. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE</code></entry>
  198. <entry><code>Zend_XmlRpc_Value_Double</code></entry>
  199. </row>
  200. <row>
  201. <entry>boolean</entry>
  202. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN</code></entry>
  203. <entry><code>Zend_XmlRpc_Value_Boolean</code></entry>
  204. </row>
  205. <row>
  206. <entry>string</entry>
  207. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRING</code></entry>
  208. <entry><code>Zend_XmlRpc_Value_String</code></entry>
  209. </row>
  210. <row>
  211. <entry>base64</entry>
  212. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64</code></entry>
  213. <entry><code>Zend_XmlRpc_Value_Base64</code></entry>
  214. </row>
  215. <row>
  216. <entry>dateTime.iso8601</entry>
  217. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME</code></entry>
  218. <entry><code>Zend_XmlRpc_Value_DateTime</code></entry>
  219. </row>
  220. <row>
  221. <entry>array</entry>
  222. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY</code></entry>
  223. <entry><code>Zend_XmlRpc_Value_Array</code></entry>
  224. </row>
  225. <row>
  226. <entry>struct</entry>
  227. <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT</code></entry>
  228. <entry><code>Zend_XmlRpc_Value_Struct</code></entry>
  229. </row>
  230. </tbody>
  231. </tgroup>
  232. </table>
  233. <para>
  234. <note>
  235. <title>自动转换</title>
  236. <para>
  237. 当创建新的 <code>Zend_XmlRpc_Value</code> 对象时,它的值通过
  238. PHP 类型设置。PHP 类型将会通过 PHP 类型转换到指定的类型。例如,
  239. 如果给 <code>Zend_XmlRpc_Value_Integer</code>
  240. 对象提供一个字符串,它将由 <code>(int)$value</code> 转换。
  241. </para>
  242. </note>
  243. </para>
  244. </sect3>
  245. </sect2>
  246. <sect2 id="zend.xmlrpc.client.requests-and-responses">
  247. <title>服务代理对象</title>
  248. <para>
  249. 另一个使用 XML-RPC 客户端调用远程方法的途径是使用服务代理。这是一个 PHP
  250. 对象代理远程 XML-RPC 名字空间,使其工作方式尽可能的贴近原始的 PHP 对象。
  251. </para>
  252. <para>
  253. 调用 <code>Zend_XmlRpc_Client</code> 实例的 <code>getProxy()</code>
  254. 方法实例化一个服务器代理。该方法将返回一个 <code>Zend_XmlRpc_Client_ServerProxy</code>
  255. 实例。对服务器代理方法的任何调用将会传递到远程,而参数的传递就如同其他任何
  256. PHP 方法一样。
  257. </para>
  258. <example id="zend.xmlrpc.client.requests-and-responses.example-1">
  259. <title>代理默认命名空间</title>
  260. <programlisting role="php"><![CDATA[
  261. require_once 'Zend/XmlRpc/Client.php';
  262. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  263. $server = $client->getProxy(); // Proxy the default namespace
  264. $hello = $server->test->sayHello(1, 2); // test.Hello(1, 2) returns "hello"
  265. ]]>
  266. </programlisting>
  267. </example>
  268. <para>
  269. <code>getProxy()</code> 方法接受一个可选参数作为将要代理的远端服务器的命名空间。
  270. 如果没有指定这个命名空间,默认的命名空间会被代理。在下面的例子中,命名空间
  271. <code>test</code> 将会被代理。
  272. </para>
  273. <example id="zend.xmlrpc.client.requests-and-responses.example-2">
  274. <title>代理任意命名空间</title>
  275. <programlisting role="php"><![CDATA[
  276. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  277. $test = $client->getProxy('test'); // Proxy the "test" namespace
  278. $hello = $test->sayHello(1, 2); // test.Hello(1,2) returns "hello"
  279. ]]>
  280. </programlisting>
  281. </example>
  282. <para>
  283. 若远端服务器支持任意深度嵌套的命名空间,仍然可以通过服务器代理使用。例如,
  284. 如果上面的例子有一个方法 <code>test.foo.bar()</code>,则可以使用
  285. <code>$test->foo->bar()</code> 来调用。
  286. </para>
  287. </sect2>
  288. <sect2 id="zend.xmlrpc.client.error-handling">
  289. <title>错误处理</title>
  290. <para>
  291. 在 XML-RPC 方法中可能出现两种错误:HTTP 错误和 XML-RPC 失败。
  292. <code>Zend_XmlRpc_Client</code> 可以识别并分别检测并捕获它们。
  293. </para>
  294. <sect3 id="zend.xmlrpc.client.error-handling.http">
  295. <title>HTTP 错误</title>
  296. <para>
  297. 当 HTTP 错误发生时,例如远端 HTTP 服务器返回
  298. <code>404 Not Found</code>,将会抛出一个
  299. <code>Zend_XmlRpc_Client_HttpException</code> 异常。
  300. </para>
  301. <example id="zend.xmlrpc.client.error-handling.http.example-1">
  302. <title>处理 HTTP 错误</title>
  303. <programlisting role="php"><![CDATA[
  304. $client = new Zend_XmlRpc_Client('http://foo/404');
  305. try {
  306. $client->call('bar', array($arg1, $arg2));
  307. } catch (Zend_XmlRpc_Client_HttpException $e) {
  308. // $e->getCode() returns 404
  309. // $e->getMessage() returns "Not Found"
  310. }
  311. ]]>
  312. </programlisting>
  313. </example>
  314. <para>
  315. 不论是如何使用 XML-RPC 客户端的,当 HTTP 错误发生时,都会抛出
  316. <code>Zend_XmlRpc_Client_HttpException</code> 异常。
  317. </para>
  318. </sect3>
  319. <sect3 id="zend.xmlrpc.client.error-handling.faults">
  320. <title>XML-RPC 失败</title>
  321. <para>
  322. XML-RPC 失败类似于 PHP 异常。它是从 XML-RPC 方法调用返回的,有着指定的类型,
  323. 同时具有错误代码和错误消息。XML-RPC 失败的处理方式随着 <code>Zend_XmlRpc_Client</code>
  324. 使用方式不同而不同。
  325. </para>
  326. <para>
  327. 当 <code>call()</code> 方法或者服务器代理对象被使用时,XML-RPC
  328. 失败会抛出一个 <code>Zend_XmlRpc_Client_FaultException</code>
  329. 异常。异常代码和消息会直接映射到原始的 XML-RPC 失败相应的内容上去。
  330. </para>
  331. <example id="zend.xmlrpc.client.error-handling.faults.example-1">
  332. <title>处理 XML-RPC 失败</title>
  333. <programlisting role="php"><![CDATA[
  334. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  335. try {
  336. $client->call('badMethod');
  337. } catch (Zend_XmlRpc_Client_FaultException $e) {
  338. // $e->getCode() returns 1
  339. // $e->getMessage() returns "Unknown method"
  340. }
  341. ]]>
  342. </programlisting>
  343. </example>
  344. <para>
  345. 当请求时使用 <code>call()</code> 方法,会在失败的时候抛出
  346. <code>Zend_XmlRpc_Client_FaultException</code> 异常。可以调用
  347. <code>getLastResponse()</code> 获得包含在 <code>Zend_XmlRpc_Response</code>
  348. 对象中的异常。
  349. </para>
  350. <para>
  351. 当请求时使用 <code>doRequest()</code> 方法,则不会抛出异常。将返回一个包含错误信息的
  352. <code>Zend_XmlRpc_Response</code> 对象。可以使用 <code>Zend_XmlRpc_Response</code>
  353. 示例的 <code>isFault()</code> 方法检查。
  354. </para>
  355. </sect3>
  356. </sect2>
  357. <sect2 id="zend.xmlrpc.client.introspection">
  358. <title>服务器自省(introspection)</title>
  359. <para>
  360. 一些 XML-RPC 服务器支持 <code>system.</code> 命名空间下的自省。<code>Zend_XmlRpc_Client</code>
  361. 对这些服务器的这种功能特别进行了支持。
  362. </para>
  363. <para>
  364. 调用 <code>Zend_XmlRpcClient</code> 的 <code>getIntrospector()</code>
  365. 方法可以获得 <code>Zend_XmlRpc_Client_ServerIntrospection</code> 实例。
  366. 通过它可以使用服务器的自省功能。
  367. </para>
  368. </sect2>
  369. <sect2 id="zend.xmlrpc.client.request-to-response">
  370. <title>从请求作出回应</title>
  371. <para>
  372. 本质上说,<code>Zend_XmlRpc_Client</code> 实例的 <code>call()</code>
  373. 方法创建了请求对象(<code>Zend_XmlRpc_Request</code>)并将其传递给另一个方法
  374. <code>doRequest()</code>,<code>doRequest()</code> 方法返回响应对象(<code>Zend_XmlRpc_Response</code>)。
  375. </para>
  376. <para>
  377. <code>doRequest()</code> 方法也可直接调用。
  378. </para>
  379. <example id="zend.xmlrpc.client.request-to-response.example-1">
  380. <title>处理请求作出回应</title>
  381. <programlisting role="php"><![CDATA[
  382. $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
  383. $request = new Zend_XmlRpc_Request();
  384. $request->setMethod('test.sayHello');
  385. $request->setParams(array('foo', 'bar'));
  386. $client->doRequest($request);
  387. // $server->getLastRequest() returns instanceof Zend_XmlRpc_Request
  388. // $server->getLastResponse() returns instanceof Zend_XmlRpc_Response
  389. ]]>
  390. </programlisting>
  391. </example>
  392. <para>
  393. 无论客户端通过任何方法调用 XML-RPC 方法,如 <code>call()</code> 方法、
  394. <code>doRequest()</code> 方法或者服务器代理,最后一个请求对象以及对应的响应对象总是可以分别调用
  395. <code>getLastRequest()</code> 和 <code>getLastResponse()</code> 获得。
  396. </para>
  397. </sect2>
  398. <sect2 id="zend.xmlrpc.client.http-client">
  399. <title>HTTP 客户端和测试</title>
  400. <para>
  401. 在前面所有的例子中,从未指定 HTTP 客户端。这是因为在使用 <code>Zend_XmlRpc_Client</code>
  402. 时会使用默认配置自动创建一个 <code>Zend_Http_Client</code> 实例。
  403. </para>
  404. <para>
  405. 可以在任何时候使用 <code>getHttpClient()</code> 方法获得 HTTP 客户端。
  406. 多数情况下默认的 HTTP 客户端已经足够使用。不过仍然可以使用 <code>setHttpClient()</code>
  407. 方法设置新的 HTTP 客户端实例。
  408. </para>
  409. <para>
  410. <code>setHttpClient()</code> 在单元测试时特别有用。在 <code>Zend_Http_Client_Adapter_Test</code>
  411. 中测试时可以欺骗远程服务器。阅读 <code>Zend_XmlRpc_Client</code> 的单元测试了解如何这样做。
  412. </para>
  413. </sect2>
  414. </sect1>
  415. <!--
  416. vim:se ts=4 sw=4 et:
  417. -->