1 <?xml version="1.0" encoding="UTF-8"?>
3 <sect1 id="zend.xmlrpc.client">
4 <title>Zend_XmlRpc_Client</title>
6 <sect2 id="zend.xmlrpc.client.introduction">
7 <title>Введение</title>
10 Zend Framework поддерживает клиентское использование удаленных
11 XML-RPC сервисов через пакет <classname>Zend_XmlRpc_Client</classname>.
12 Его основные возможности включают в себя автоматическое
13 преобразование типов между PHP и XML-RPC, прокси-объект сервера и
14 доступ к средствам интроспекции на сервере.
20 <sect2 id="zend.xmlrpc.client.method-calls">
21 <title>Вызов методов</title>
24 Конструктор <classname>Zend_XmlRpc_Client</classname> принимает URL удаленного
25 XML-RPC сервера в качестве первого параметра. Новый экземпляр класса
26 может использоваться для вызова любых удаленных методов этого
31 Для вызова удаленного метода через клиентa XML-RPC инстанцируйте его
32 и используйте его метод <code>call()</code>. В примере ниже
33 используется демонстрационный XML-RPC сервер на веб-сайте Zend
34 Framework. Вы можете использовать его для тестирования или изучения
35 компонент <classname>Zend_XmlRpc</classname>.
38 <example id="zend.xmlrpc.client.method-calls.example-1">
39 <title>Вызов метода XML-RPC</title>
40 <programlisting language="php"><![CDATA[
41 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
43 echo $client->call('test.sayHello');
50 Значение XML-RPC, возвращаемое при вызове удаленного метода, будет
51 автоматически приведено к эквивалентному типу в PHP. В примере выше
52 возвращается строка (тип <type>String</type> в PHP), и она уже
57 Первый параметр метода <code>call()</code> принимает имя удаленного
58 метода, вызов которого требуется. Если удаленный метод требует
59 каких-либо параметров, то они могут быть переданы методу
60 <code>call()</code> через второй необязательный параметр в виде
61 массива значений для последующей передачи удаленному методу:
64 <example id="zend.xmlrpc.client.method-calls.example-2">
65 <title>Вызов метода XML-RPC с параметрами</title>
66 <programlisting language="php"><![CDATA[
67 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
72 $result = $client->call('test.sayHello', array($arg1, $arg2));
74 // возвращаемый результат имеет "родной" для PHP тип
79 Если удаленный метод не требует параметров, то этот необязательный
80 параметр можно опустить или передать пустой массив. Массив
81 параметров для удаленного метода может содержать значения "родного"
82 для PHP типа, объекты <classname>Zend_XmlRpc_Value</classname>, либо
87 Метод <code>call()</code> будет автоматически преобразовывать ответ
88 XML-RPC и возвращать его в эквивалентном "родном" для PHP типе.
89 Кроме этого, можно получить объект <classname>Zend_XmlRpc_Response</classname>
90 для возвращенного значения, вызвав метод
91 <code>getLastResponse()</code> после вызова <code>call()</code>.
95 <sect2 id="zend.xmlrpc.value.parameters">
96 <title>Типы и их преобразование</title>
98 Некоторые удаленные методы требуют передачи параметров при вызове.
99 Они передаются методу <code>call()</code> объекта
100 <classname>Zend_XmlRpc_Client</classname> в виде массива во втором параметре.
101 Любой параметр может быть передан в "родном" для PHP типе, который
102 будет автоматически преобразован в соответствующий тип XML-RPC,
103 или как объект, представляющий
104 определенный тип в XML-RPC (один из объектов
105 <classname>Zend_XmlRpc_Value</classname>).
108 <sect3 id="zend.xmlrpc.value.parameters.php-native">
109 <title>Параметры в "родном" для PHP типе</title>
111 Параметры могут передаваться методу <code>call()</code> как
112 переменные "родного" для PHP типа, это могут быть типы
113 <type>String</type>, <code>integer</code>, <code>float</code>,
114 <type>Boolean</type>, <type>Array</type> или
115 <code>object</code>. В этом случае каждый из этих типов будет
116 автоматически определен и преобразован в один из типов XML-RPC
117 согласно следующей таблице:
121 <title>Преобразование типов PHP и XML-RPC</title>
125 <entry>Тип в PHP</entry>
126 <entry>Тип в XML-RPC</entry>
131 <entry>integer</entry>
135 <entry>double</entry>
136 <entry>double</entry>
139 <entry>boolean</entry>
140 <entry>boolean</entry>
143 <entry>string</entry>
144 <entry>string</entry>
151 <entry>array (ассоциативный)</entry>
152 <entry>struct</entry>
155 <entry>object</entry>
163 <title>Какому типу будет соответствовать пустой массив?</title>
166 Передача пустого массива методу XML-RPC несет в себе
167 потенциальную проблему, т.к. он может быть представлен
168 и массивом, и структурой. <classname>Zend_XmlRpc_Client</classname>
169 в этом случае делает запрос к методу сервера
170 <code>system.methodSignature</code> для определения
171 требуемого типа аргумента и производит соответствующее
176 Но такое решение само по себе тоже может быть источником
177 проблем. Во-первых, сервера, которые не поддерживают метод
178 <code>system.methodSignature</code>, будут журналировать это
179 как ошибочные вызовы, в этом случае
180 <classname>Zend_XmlRpc_Client</classname> будет производить
181 преобразование значения к типу array в XML-RPC.
182 Кроме того, это приводит к дополнительным вызовам к
183 удаленному серверу в случае передачи аргументов в виде
188 Для того, чтобы полностью отключить эти вызовы, вы можете
189 вызвать метод <code>setSkipSystemLookup()</code> до
190 собственно запроса к методу XML-RPC:
193 <programlisting language="php"><![CDATA[
194 $client->setSkipSystemLookup(true);
195 $result = $client->call('foo.bar', array(array()));
201 <sect3 id="zend.xmlrpc.value.parameters.xmlrpc-value">
202 <title>Параметры в виде объектов Zend_XmlRpc_Value</title>
204 Параметры могут также создаваться как экземпляры
205 <classname>Zend_XmlRpc_Value</classname> для точного указания типа
206 XML-RPC. Основные причины для этого:
211 Вы хотите быть уверенными в том, что
212 процедуре передается корректный тип параметра
213 (т.е. процедура требует целочисленное значение, а
214 вы можете получать его из БД в виде
220 Удаленная процедура требует тип <code>base64</code>
221 или <code>dateTime.iso8601</code> (которых нет среди
222 "родных" для PHP типов).
227 Автоматическое преобразование может работать
228 неправильно (например, вы хотите передать пустую
229 структуру XML-RPC в качестве параметра. Пустая структура
230 представляется в PHP пустым массивом, но если вы
231 передаете пустой массив в качестве параметра, то он
232 преобразовывается в массив XML-RPC, т.к. не
233 является ассоциативным массивом)
240 Есть два способа создания объектов <classname>Zend_XmlRpc_Value</classname> ―
241 непосредственное инстанцирование одного из подклассов
242 <classname>Zend_XmlRpc_Value</classname> и использование статического
244 <classname>Zend_XmlRpc_Value::getXmlRpcValue()</classname>.
247 <table id="zend.xmlrpc.value.parameters.xmlrpc-value.table-1">
248 <title>Объекты Zend_XmlRpc_Value для типов XML-RPC</title>
252 <entry>Тип XML-RPC</entry>
253 <entry>Константа <classname>Zend_XmlRpc_Value</classname></entry>
254 <entry>Объект <classname>Zend_XmlRpc_Value</classname></entry>
260 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER</code></entry>
261 <entry><classname>Zend_XmlRpc_Value_Integer</classname></entry>
264 <entry>double</entry>
265 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE</code></entry>
266 <entry><classname>Zend_XmlRpc_Value_Double</classname></entry>
269 <entry>boolean</entry>
270 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN</code></entry>
271 <entry><classname>Zend_XmlRpc_Value_Boolean</classname></entry>
274 <entry>string</entry>
275 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRING</code></entry>
276 <entry><classname>Zend_XmlRpc_Value_String</classname></entry>
279 <entry>base64</entry>
280 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64</code></entry>
281 <entry><classname>Zend_XmlRpc_Value_Base64</classname></entry>
284 <entry>dateTime.iso8601</entry>
285 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME</code></entry>
286 <entry><classname>Zend_XmlRpc_Value_DateTime</classname></entry>
290 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY</code></entry>
291 <entry><classname>Zend_XmlRpc_Value_Array</classname></entry>
294 <entry>struct</entry>
295 <entry><code>Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT</code></entry>
296 <entry><classname>Zend_XmlRpc_Value_Struct</classname></entry>
304 <title>Автоматическое преобразование</title>
306 Когда создается новый объект
307 <classname>Zend_XmlRpc_Value</classname>, его значение
308 устанавливается в "родном" для PHP типе. Тип в PHP будет
309 преобразован к определенному типу средствами PHP.
310 Например, если в качестве значения для объекта
311 <classname>Zend_XmlRpc_Value_Integer</classname> была передана
312 строка, то она будет преобразована через
313 <code>(int)$value</code>.
320 <sect2 id="zend.xmlrpc.client.requests-and-responses">
321 <title>Прокси-объект сервера</title>
323 Другим способом вызова удаленных методов через клиента XML-RPC
324 является использование "заместителя" сервера. Это PHP-объект,
325 который предоставляет интерфейс к удаленному пространству имен
326 XML-RPC, делая работу с ним максимально близкой к работе с обычным
331 Для того, чтобы инстанцировать "заместителя" сервера, вызовите
332 метод <code>getProxy()</code> объекта
333 <classname>Zend_XmlRpc_Client</classname>. Он вернет объект класса
334 <classname>Zend_XmlRpc_Client_ServerProxy</classname>.
335 Любые вызовы методов прокси-объекта
336 сервера будет перенаправлены к удаленному серверу, параметры могут
337 передаваться так же, как и для любых других методов в PHP.
340 <example id="zend.xmlrpc.client.requests-and-responses.example-1">
341 <title>Прокси-объект к пространству имен по умолчанию</title>
342 <programlisting language="php"><![CDATA[
343 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
345 // Создание прокси-объекта к пространству имен по умолчанию
346 $server = $client->getProxy();
348 $hello = $server->test->sayHello(1, 2);
349 // test.Hello(1, 2) возвращает "hello"
354 Метод <code>getProxy()</code> принимает необязательный аргумент,
355 указывающий, к какому пространству имен следует создать
356 прокси-объект. Если этот аргумент не был указан, то то будет
357 использоваться пространство имен по умолчанию. В следующем примере
358 используется пространство имен <code>test</code>:
361 <example id="zend.xmlrpc.client.requests-and-responses.example-2">
362 <title>Прокси-объект к произвольному пространству имен</title>
363 <programlisting language="php"><![CDATA[
364 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
366 // Создание прокси-объекта к пространству имен "test"
367 $test = $client->getProxy('test');
369 $hello = $test->sayHello(1, 2);
370 // test.Hello(1,2) возвращает "hello"
375 Если удаленный сервер поддерживает сколько угодно вложенные
376 пространства имен, то они также могут использоваться через
377 прокси-объект сервера. Например, если сервер в примере выше имеет
378 метод <code>test.foo.bar()</code>, то он может вызываться следующим
379 образом: <varname>$test->foo->bar()</varname>.
384 <sect2 id="zend.xmlrpc.client.error-handling">
385 <title>Обработка ошибок</title>
387 При вызове методов XML-RPC могут могут быть ошибки двух типов: HTTP и
388 XML-RPC. <classname>Zend_XmlRpc_Client</classname> распознает оба типа,
389 позволяя обнаруживать и отлавливать их независимо друг от друга.
392 <sect3 id="zend.xmlrpc.client.error-handling.http">
393 <title>Ошибки HTTP</title>
396 Если произошла ошибка HTTP - например, удаленный HTTP-сервер
397 вернул код <code>404 Not Found</code>, - то будет сгенерировано
398 исключение <classname>Zend_XmlRpc_Client_HttpException</classname>.
401 <example id="zend.xmlrpc.client.error-handling.http.example-1">
402 <title>Обработка ошибок HTTP</title>
404 <programlisting language="php"><![CDATA[
405 $client = new Zend_XmlRpc_Client('http://foo/404');
409 $client->call('bar', array($arg1, $arg2));
411 } catch (Zend_XmlRpc_HttpException $e) {
413 // $e->getCode() возвращает 404
414 // $e->getMessage() возвращает "Not Found"
421 Независимо от того, какой клиент XML-RPC используется, всякий
422 раз, когда происходит ошибка HTTP, генерируется исключение
423 <classname>Zend_XmlRpc_Client_HttpException</classname>.
427 <sect3 id="zend.xmlrpc.client.error-handling.faults">
428 <title>Ошибки XML-RPC</title>
431 Ошибка XML-RPC аналогична исключению в PHP. Это специальный тип,
432 возвращаемый при вызове метода XML-RPC и включающий в себя код и
433 сообщение ошибки. Ошибки XML-RPC обрабатываются по-разному,
434 в зависимости от контекста использования
435 <classname>Zend_XmlRpc_Client</classname>.
439 Если используется метод <code>call()</code> или прокси-объект
440 сервера, то ошибка XML-RPC приведет к тому, что будет
441 сгенерировано исключение
442 <classname>Zend_XmlRpc_Client_FaultException</classname>. Код и сообщение
443 исключения будут в точности соответствовать значениям в
444 возвращенном ответе с сообщением об ошибке.
447 <example id="zend.xmlrpc.client.error-handling.faults.example-1">
448 <title>Обработка ошибок XML-RPC</title>
450 <programlisting language="php"><![CDATA[
451 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
455 $client->call('badMethod');
457 } catch (Zend_XmlRpc_FaultException $e) {
459 // $e->getCode() возвращает 1
460 // $e->getMessage() возвращает "Unknown method"
467 Если для выполнения запроса используется метод
468 <code>call()</code>, то в случае ошибки будет сгенерировано
469 исключение <classname>Zend_XmlRpc_FaultException</classname>. Объект
470 <classname>Zend_XmlRpc_Response</classname>, содержащий возвращенную
471 ошибку, можно также получить через метод
472 <code>getLastResponse()</code>.
476 Если для выполнения запроса используется метод
477 <code>doRequest()</code>, то исключение не генерируется. Вместо
478 этого будет возвращен объект <classname>Zend_XmlRpc_Response</classname>,
479 содержащий возвращенную XML-RPC ошибку. Проверить, содержит ли
480 объект ошибку, можно через метод <code>isFault()</code> объекта
481 <classname>Zend_XmlRpc_Response</classname>.
487 <sect2 id="zend.xmlrpc.client.introspection">
488 <title>Интроспекция сервера</title>
490 Некоторые XML-RPC сервера поддерживают интроспекцию методов
491 под пространством имен <code>system.</code>.
492 <classname>Zend_XmlRpc_Client</classname> предоставляет специальную поддержку
493 для серверов с этой возможностью.
497 Экземпляр <classname>Zend_XmlRpc_Client_ServerIntrospection</classname> может
498 быть получен через вызов метода <code>getIntrospector()</code>
499 класса <classname>Zend_XmlRpcClient</classname>. Далее он может использоваться
500 для выполнения операций интроспекции на сервере.
504 <sect2 id="zend.xmlrpc.client.request-to-response">
505 <title>От запроса к ответу</title>
507 Метод <code>call()</code> экземпляра <classname>Zend_XmlRpc_Client</classname>
508 в процессе выполнения строит объект запроса
509 (<classname>Zend_XmlRpc_Request</classname>) и передает его другому методу
510 <code>doRequest()</code>, который возвращает объект ответа
511 (<classname>Zend_XmlRpc_Response</classname>).
515 Метод <code>doRequest()</code> также доступен для непосредственного
519 <example id="zend.xmlrpc.client.request-to-response.example-1">
520 <title>Выполнение запроса</title>
522 <programlisting language="php"><![CDATA[
523 $client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');
525 $request = new Zend_XmlRpc_Request();
526 $request->setMethod('test.sayHello');
527 $request->setParams(array('foo', 'bar'));
529 $client->doRequest($request);
531 // $server->getLastRequest() возвращает экземпляр Zend_XmlRpc_Request
532 // $server->getLastResponse() возвращает экземпляр Zend_XmlRpc_Response
537 После того, как через клиента был вызван метод XML-RPC (через
538 методы <code>call()</code>, <code>doRequest()</code> или через
539 прокси-объект сервера), всегда можно получить объекты последнего запроса и
540 ответа на него через методы <code>getLastRequest()</code> и
541 <code>getLastResponse()</code> соответственно.
545 <sect2 id="zend.xmlrpc.client.http-client">
546 <title>HTTP-клиент и тестирование</title>
549 Ни в одном из предыдущих примеров не указывался HTTP-клиент. В
550 этом случае создается новый экземпляр <classname>Zend_Http_Client</classname>
551 с настройками по умолчанию и автоматически используется
552 клиентом <classname>Zend_XmlRpc_Client</classname>.
556 HTTP-клиент может быть получен в любое время через метод
557 <code>getHttpClient()</code>. В большинстве случаев достаточно
558 использование HTTP-клиента по умолчанию. Тем не менее, метод
559 <code>setHttpClient()</code> позволяет установить HTTP-клиент,
560 отличный от принятого по умолчанию.
564 <code>setHttpClient()</code> может быть полезен при
565 unit-тестировании. При совместном использовании с
566 <classname>Zend_Http_Client_Adapter_Test</classname> можно имитировать
567 удаленные сервисы для тестирования. В качестве примера реализации
568 рассмотрите unit-тесты для <classname>Zend_XmlRpc_Client</classname>,
569 входящие в поставку Zend Framework.