Zend_XmlRpc_Client
Введение
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.
Вызов метода XML-RPC
call('test.sayHello');
// hello
]]>
Значение XML-RPC, возвращаемое при вызове удаленного метода, будет
автоматически приведено к эквивалентному типу в PHP. В примере выше
возвращается строка (тип String в PHP), и она уже
готова к применению.
Первый параметр метода call() принимает имя удаленного
метода, вызов которого требуется. Если удаленный метод требует
каких-либо параметров, то они могут быть переданы методу
call() через второй необязательный параметр в виде
массива значений для последующей передачи удаленному методу:
Вызов метода XML-RPC с параметрами
call('test.sayHello', array($arg1, $arg2));
// возвращаемый результат имеет "родной" для PHP тип
]]>
Если удаленный метод не требует параметров, то этот необязательный
параметр можно опустить или передать пустой массив. Массив
параметров для удаленного метода может содержать значения "родного"
для PHP типа, объекты Zend_XmlRpc_Value, либо
и то и другое вместе.
Метод call() будет автоматически преобразовывать ответ
XML-RPC и возвращать его в эквивалентном "родном" для PHP типе.
Кроме этого, можно получить объект Zend_XmlRpc_Response
для возвращенного значения, вызвав метод
getLastResponse() после вызова call().
Типы и их преобразование
Некоторые удаленные методы требуют передачи параметров при вызове.
Они передаются методу call() объекта
Zend_XmlRpc_Client в виде массива во втором параметре.
Любой параметр может быть передан в "родном" для PHP типе, который
будет автоматически преобразован в соответствующий тип XML-RPC,
или как объект, представляющий
определенный тип в XML-RPC (один из объектов
Zend_XmlRpc_Value).
Параметры в "родном" для PHP типе
Параметры могут передаваться методу call() как
переменные "родного" для PHP типа, это могут быть типы
String, integer, float,
Boolean, Array или
object. В этом случае каждый из этих типов будет
автоматически определен и преобразован в один из типов XML-RPC
согласно следующей таблице:
Преобразование типов PHP и XML-RPC
Тип в PHP
Тип в XML-RPC
integer
int
double
double
boolean
boolean
string
string
array
array
array (ассоциативный)
struct
object
array
Какому типу будет соответствовать пустой массив?
Передача пустого массива методу XML-RPC несет в себе
потенциальную проблему, т.к. он может быть представлен
и массивом, и структурой. Zend_XmlRpc_Client
в этом случае делает запрос к методу сервера
system.methodSignature для определения
требуемого типа аргумента и производит соответствующее
преобразование.
Но такое решение само по себе тоже может быть источником
проблем. Во-первых, сервера, которые не поддерживают метод
system.methodSignature, будут журналировать это
как ошибочные вызовы, в этом случае
Zend_XmlRpc_Client будет производить
преобразование значения к типу array в XML-RPC.
Кроме того, это приводит к дополнительным вызовам к
удаленному серверу в случае передачи аргументов в виде
массивов.
Для того, чтобы полностью отключить эти вызовы, вы можете
вызвать метод setSkipSystemLookup() до
собственно запроса к методу XML-RPC:
setSkipSystemLookup(true);
$result = $client->call('foo.bar', array(array()));
]]>
Параметры в виде объектов 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().
Объекты 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.
Прокси-объект сервера
Другим способом вызова удаленных методов через клиента XML-RPC
является использование "заместителя" сервера. Это PHP-объект,
который предоставляет интерфейс к удаленному пространству имен
XML-RPC, делая работу с ним максимально близкой к работе с обычным
объектом в PHP.
Для того, чтобы инстанцировать "заместителя" сервера, вызовите
метод getProxy() объекта
Zend_XmlRpc_Client. Он вернет объект класса
Zend_XmlRpc_Client_ServerProxy.
Любые вызовы методов прокси-объекта
сервера будет перенаправлены к удаленному серверу, параметры могут
передаваться так же, как и для любых других методов в PHP.
Прокси-объект к пространству имен по умолчанию
getProxy();
$hello = $server->test->sayHello(1, 2);
// test.Hello(1, 2) возвращает "hello"
]]>
Метод getProxy() принимает необязательный аргумент,
указывающий, к какому пространству имен следует создать
прокси-объект. Если этот аргумент не был указан, то то будет
использоваться пространство имен по умолчанию. В следующем примере
используется пространство имен test:
Прокси-объект к произвольному пространству имен
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 - например, удаленный HTTP-сервер
вернул код 404 Not Found, - то будет сгенерировано
исключение Zend_XmlRpc_Client_HttpException.
Обработка ошибок HTTP
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
Ошибка XML-RPC аналогична исключению в PHP. Это специальный тип,
возвращаемый при вызове метода XML-RPC и включающий в себя код и
сообщение ошибки. Ошибки XML-RPC обрабатываются по-разному,
в зависимости от контекста использования
Zend_XmlRpc_Client.
Если используется метод call() или прокси-объект
сервера, то ошибка XML-RPC приведет к тому, что будет
сгенерировано исключение
Zend_XmlRpc_Client_FaultException. Код и сообщение
исключения будут в точности соответствовать значениям в
возвращенном ответе с сообщением об ошибке.
Обработка ошибок XML-RPC
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() также доступен для непосредственного
использования:
Выполнение запроса
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-клиент и тестирование
Ни в одном из предыдущих примеров не указывался HTTP-клиент. В
этом случае создается новый экземпляр Zend_Http_Client
с настройками по умолчанию и автоматически используется
клиентом Zend_XmlRpc_Client.
HTTP-клиент может быть получен в любое время через метод
getHttpClient(). В большинстве случаев достаточно
использование HTTP-клиента по умолчанию. Тем не менее, метод
setHttpClient() позволяет установить HTTP-клиент,
отличный от принятого по умолчанию.
setHttpClient() может быть полезен при
unit-тестировании. При совместном использовании с
Zend_Http_Client_Adapter_Test можно имитировать
удаленные сервисы для тестирования. В качестве примера реализации
рассмотрите unit-тесты для Zend_XmlRpc_Client,
входящие в поставку Zend Framework.