Zend Framework поддерживает клиентское использование удаленных
XML-RPC сервисов через пакет Zend_XmlRpc_Client
.
Его основные возможности включают в себя автоматическое
преобразование типов между PHP и XML-RPC, прокси-объект сервера и
доступ к средствам интроспекции на сервере.
Конструктор 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()
.
Некоторых удаленных методов требуют передачи параметров при вызове.
Они предоставляются методу call()
объекта
Zend_XmlRpc_Client
в виде массива во втором параметре.
Каждый параметр может быть передан в "родном" для PHP типе, который
будет автоматически преобразован, или как объект, представляющий
определенный тип в XML-RPC (один из объектов
Zend_XmlRpc_Value
).
Параметры могут передаваться методу call()
как
переменные "родного" для PHP типа, это могут быть типы
string
, integer
, float
,
boolean
, array
или
object
. В этом случае каждый из этих типов будет
автоматически определен и преобразован в один из типов XML-RPC
согласно этой таблице:
Параметры могут также создаваться как экземпляры
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 |
Автоматическое преобразование | |
---|---|
Когда создается новый объект
|
Другим способом вызова удаленных методов через клиента 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()
.
При вызове методов XML-RPC могут происходить два типа ошибок: HTTP и
XML-RPC. Zend_XmlRpc_Client
распознает оба типа,
позволяя обнаруживать и отлавливать их независимо друг от друга.
Если произошла ошибка 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
.
Ошибка 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
.
Некоторые XML-RPC сервера де-факто поддерживают интроспекцию методов
под пространством имен system.
.
Zend_XmlRpc_Client
предоставляет специальную поддержку
для серверов с этой возможностью.
Экземпляр Zend_XmlRpc_Client_ServerIntrospection
может
быть получен через вызов метода getIntrospector()
класса Zend_XmlRpcClient
. Далее он может использоваться
для выполнения операций интроспекции на сервере.
Метод 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()
соответственно.
Ни в одном из предыдущих примеров не указывался HTTP-клиент. В
этом случае создается новый экземпляр Zend_Http_Client
с настройками по умолчанию и автоматически используется
клиентом Zend_XmlRpc_Client
.
HTTP-клиент может быть получен в любое время через метод
getHttpClient()
. В большинстве случаев достаточно
использование HTTP-клиента по умолчанию. Тем не менее, метод
setHttpClient()
позволяет установить HTTP-клиент,
отличный от принятого по умолчанию.
setHttpClient()
может быть полезен при
unit-тестировании. При совместном использовании с
Zend_Http_Client_Adapter_Test
можно имитировать
удаленные сервисы для тестирования. За примером того, как можно это
реализовать, см. unit-тесты для Zend_XmlRpc_Client
.