36.2. Zend_XmlRpc_Client

36.2.1. Введение

Zend Framework поддерживает клиентское использование удаленных XML-RPC сервисов через пакет Zend_XmlRpc_Client. Его основные возможности включают в себя автоматическое преобразование типов между PHP и XML-RPC, прокси-объект сервера и доступ к средствам интроспекции на сервере.

36.2.2. Вызов методов

Конструктор Zend_XmlRpc_Client принимает URL удаленного XML-RPC сервера в качестве первого параметра. Новый экземпляр класса может использоваться для вызова любых удаленных методов этого сервера.

Для вызова удаленного метода через клиентa XML-RPC инстанцируйте его и используйте его метод call(). В примере ниже используется демонстрационный XML-RPC сервер на веб-сайте Zend Framework. Вы можете использовать его для тестирования или изучения компонент Zend_XmlRpc.

Пример 36.1. Вызов метода XML-RPC

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

echo $client->call('test.sayHello'); 

// hello

?>

Значение XML-RPC, возвращаемое при вызове удаленного метода, будет автоматически приведено к эквивалентному типу в PHP. В примере выше возвращается строка (тип string в PHP), и она уже готова к применению.

Первый параметр метода call() принимает имя удаленного метода, вызов которого требуется. Если удаленный метод требует каких-либо параметров, то они могут быть переданы методу call() через второй необязательный параметр в виде массива значений для последующей передачи удаленному методу:

Пример 36.2. Вызов метода XML-RPC с параметрами

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$arg1 = 1.1;
$arg2 = 'foo';

$result = $client->call('test.sayHello', array($arg1, $arg2)); 

?>

Если удаленный метод не требует параметров, то этот необязательный параметр можно опустить или передать пустой массив. Массив параметров для удаленного метода может содержать значения "родного" для PHP типа, объекты Zend_XmlRpc_Value, либо и то и другое вместе.

Метод call() будет автоматически преобразовывать ответ XML-RPC и возвращать его в эквивалентном "родном" для PHP типе. Кроме этого, можно получить объект Zend_XmlRpc_Response для возвращенного значения, вызвав метод getLastResponse() после вызова call().

36.2.3. Типы и их преобразование

Некоторых удаленных методов требуют передачи параметров при вызове. Они предоставляются методу call() объекта Zend_XmlRpc_Client в виде массива во втором параметре. Каждый параметр может быть передан в "родном" для PHP типе, который будет автоматически преобразован, или как объект, представляющий определенный тип в XML-RPC (один из объектов Zend_XmlRpc_Value).

36.2.3.1. Параметры в "родном" для PHP типе

Параметры могут передаваться методу call() как переменные "родного" для PHP типа, это могут быть типы string, integer, float, boolean, array или object. В этом случае каждый из этих типов будет автоматически определен и преобразован в один из типов XML-RPC согласно этой таблице:

Таблица 36.1. Преобразование типов PHP и XML-RPC

Тип в PHP Тип в XML-RPC
integer int
double double
boolean boolean
string string
array array
array (ассоциативный) struct
object array

36.2.3.2. Параметры в виде объектов Zend_XmlRpc_Value

Параметры могут также создаваться как экземпляры Zend_XmlRpc_Value для точного указания типа XML-RPC. Основные причины для этого:

  • Вы хотите быть уверенными в том, что процедуре передается корректный тип параметра (т.е. процедура требует целочисленное значение, а вы можете получать его из БД в виде строки)

  • Удаленная процедура требует тип base64 или dateTime.iso8601 (которых нет среди "родных" для PHP типов).

  • Автоматическое преобразование может работать неправильно (например, вы хотите передать пустую структуру XML-RPC как параметр. Пустая структура представляется в PHP пустым массивом, но когда вы передаете пустой массив как параметр, он будет преобразован в массив XML-RPC, так как не является ассоциативным массивом)

Есть два пути создания объектов Zend_XmlRpc_Value ― непосредственное инстанцирование одного из подклассов Zend_XmlRpc_Value и использование статического фабричного метода Zend_XmlRpc_Value::getXmlRpcValue().

Таблица 36.2. Объекты Zend_XmlRpc_Value для типов XML-RPC

Тип XML-RPC Константа Zend_XmlRpc_Value Объект Zend_XmlRpc_Value
int Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER Zend_XmlRpc_Value_Integer
double Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE Zend_XmlRpc_Value_Double
boolean Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN Zend_XmlRpc_Value_Boolean
string Zend_XmlRpc_Value::XMLRPC_TYPE_STRING Zend_XmlRpc_Value_String
base64 Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64 Zend_XmlRpc_Value_Base64
dateTime.iso8601 Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME Zend_XmlRpc_Value_DateTime
array Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY Zend_XmlRpc_Value_Array
struct Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT Zend_XmlRpc_Value_Struct

[Замечание] Автоматическое преобразование

Когда создается новый объект Zend_XmlRpc_Value, его значение устанавливается в "родном" для PHP типе. Тип в PHP будет преобразован к определенному типу средствами PHP. Например, если в качестве значения для объекта Zend_XmlRpc_Value_Integer была передана строка, то она будет преобразована с помощью (int)$value.

36.2.4. Прокси-объект сервера

Другим способом вызова удаленных методов через клиента XML-RPC является использование "заместителя" сервера. Это PHP-объект, который предоставляет интерфейс к удаленному пространству имен XML-RPC, делая работу с ним настолько близкой к работе с обычным объектом в PHP, насколько это возможно.

Для того, чтобы инстанцировать "заместителя" сервера, вызовите метод getProxy() объекта Zend_XmlRpc_Client. Любые вызовы методов прокси-объекта сервера будет перенаправлены к удаленному серверу, параметры могут передаваться так же, как и для любых других методов в PHP.

Пример 36.3. Прокси-объект к пространству имен по умолчанию

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

// Создание прокси-объекта к пространству имен по умолчанию
$server = $client->getProxy();

$hello = $server->test->sayHello(1, 2);
// test.Hello(1, 2) возвращает "hello"

?>
            

Метод getProxy() принимает необязательный аргумент, указывающий, к какому пространству имен следует создать прокси-объект. Если этот аргумент не был указан, то то будет использоваться пространство имен по умолчанию. В следующем примере используется пространство имен test.

Пример 36.4. Прокси-объект к любому пространству имен

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

// ... Proxy the "test" namespace
$test  = $client->getProxy('test');

$hello = $test->sayHello(1, 2);
// test.Hello(1,2) возвращает "hello"

?>

Если удаленный сервер поддерживает сколько угодно вложенные пространства имен, то они также могут использоваться через прокси-объект сервера. Например, если сервер в примере выше имеет метод test.foo.bar(), то он может вызываться следующим образом: $test->foo->bar().

36.2.5. Обработка ошибок

При вызове методов XML-RPC могут происходить два типа ошибок: HTTP и XML-RPC. Zend_XmlRpc_Client распознает оба типа, позволяя обнаруживать и отлавливать их независимо друг от друга.

36.2.5.1. Ошибки HTTP

Если произошла ошибка HTTP, например, удаленный HTTP-сервер вернул код 404 Not Found, то будет сгенерировано исключение Zend_XmlRpc_Client_HttpException.

Пример 36.5. Обработка ошибок HTTP

<?php

require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://foo/404');

try {

    $client->call('bar', array($arg1, $arg2));

} catch (Zend_XmlRpc_HttpException $e) {
    
    // $e->getCode() возвращает 404
    // $e->getMessage() возвращает "Not Found"
    
}

?>

Независимо от того, какой клиент XML-RPC используется, всякий раз, когда происходит ошибка HTTP, генерируется исключение Zend_XmlRpc_Client_HttpException.

36.2.5.2. Ошибки XML-RPC

Ошибка XML-RPC аналогична исключению в PHP. Это специальный тип, возвращаемый при вызове метода XML-RPC и включающий в себя код и сообщение ошибки. Ошибки XML-RPC обрабатываются по-разному в зависимости от контекста использования Zend_XmlRpc_Client.

Если используется метод call() или прокси-объект сервера, то ошибка XML-RPC приведет к тому, что будет сгенерировано исключение Zend_XmlRpc_Client_FaultException. Код и сообщение исключения будут в точности соответствовать значениям в возвращенном ответе с сообщением об ошибке.

Пример 36.6. Обработка ошибок XML-RPC

<?php
                                
require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

try {

    $client->call('badMethod');

} catch (Zend_XmlRpc_FaultException $e) {
    
    // $e->getCode() возвращает 1
    // $e->getMessage() возвращает "Unknown method"
    
}

?>

Если для выполнения запроса используется метод call(), то в случае ошибки будет сгенерировано исключение Zend_XmlRpc_FaultException. Объект Zend_XmlRpc_Response, содержащий возвращенную ошибку, можно также получить через метод getLastResponse().

Если для выполнения запроса используется метод doRequest(), то исключение не генерируется. Вместо этого будет возвращен объект Zend_XmlRpc_Response, содержащий возвращенную XML-RPC ошибку. Проверить, содержит ли объект ошибку, можно через метод isFault() объекта Zend_XmlRpc_Response.

36.2.6. Интроспекция сервера

Некоторые XML-RPC сервера де-факто поддерживают интроспекцию методов под пространством имен system.. Zend_XmlRpc_Client предоставляет специальную поддержку для серверов с этой возможностью.

Экземпляр Zend_XmlRpc_Client_ServerIntrospection может быть получен через вызов метода getIntrospector() класса Zend_XmlRpcClient. Далее он может использоваться для выполнения операций интроспекции на сервере.

36.2.7. От запроса к ответу

Метод call() экземпляра Zend_XmlRpc_Client в процессе выполнения строит объект запроса (Zend_XmlRpc_Request) и передает его другому методу doRequest(), который возвращает объект ответа (Zend_XmlRpc_Response).

Метод doRequest() также доступен для непосредственного использования:

Пример 36.7. Выполнение запроса

<?php
                                
require_once 'Zend/XmlRpc/Client.php';

$client = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

$request = new Zend_XmlRpc_Request();
$request->setMethod('test.sayHello');
$request->setParams(array('foo', 'bar'));

$client->doRequest($request);

// $server->getLastRequest() возвращает экземпляр Zend_XmlRpc_Request
// $server->getLastResponse() возвращает экземпляр Zend_XmlRpc_Response

?>

Всегда после того, как через клиента был вызван метод XML-RPC (через методы call(), doRequest() или через прокси-объект сервера), можно получить объекты последнего запроса и ответа на него через методы getLastRequest() и getLastResponse() соответственно.

36.2.8. HTTP-клиент и тестирование

Ни в одном из предыдущих примеров не указывался HTTP-клиент. В этом случае создается новый экземпляр Zend_Http_Client с настройками по умолчанию и автоматически используется клиентом Zend_XmlRpc_Client.

HTTP-клиент может быть получен в любое время через метод getHttpClient(). В большинстве случаев достаточно использование HTTP-клиента по умолчанию. Тем не менее, метод setHttpClient() позволяет установить HTTP-клиент, отличный от принятого по умолчанию.

setHttpClient() может быть полезен при unit-тестировании. При совместном использовании с Zend_Http_Client_Adapter_Test можно имитировать удаленные сервисы для тестирования. За примером того, как можно это реализовать, см. unit-тесты для Zend_XmlRpc_Client.