| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.xmlrpc.server">
- <title>Zend_XmlRpc_Server</title>
- <sect2 id="zend.xmlrpc.server.introduction">
- <title>Введение</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> задуман как полнофункциональный XML-RPC сервер,
- следующий <ulink url="http://www.xmlrpc.com/spec">спецификациям,
- приведенным на www.xmlrpc.com</ulink>. Кроме того, он реализует метод
- <code>system.multicall()</code>, позволяющий объединять несколько
- запросов в один.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.usage">
- <title>Основы использования</title>
- <para>
- Простой пример использования:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_XmlRpc_Server();
- $server->setClass('My_Service_Class');
- echo $server->handle();
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.xmlrpc.server.structure">
- <title>Структура сервера</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> состоит из множества компонент от собственно
- сервера до объектов запросов, ответов и сообщений об ошибке.
- </para>
- <para>
- Для загрузки <classname>Zend_XmlRpc_Server</classname> разработчик должен прикрепить классы
- или функции к серверу через методы <code>setClass()</code> и
- <code>addFunction()</code>.
- </para>
- <para>
- После этого можно передать объект <classname>Zend_XmlRpc_Request</classname>
- методу <code>Zend_XmlRpc_Server::handle()</code>; если он не был
- передан, то будет проинциализирован объект
- <classname>Zend_XmlRpc_Request_Http</classname>, при этом данные запроса
- берутся из <code>php://input</code>.
- </para>
- <para>
- Затем <code>Zend_XmlRpc_Server::handle()</code> пытается определить
- подходящий обработчик, основываясь на запрошенном методе. После
- этого он возвращает объект ответа, основанный на
- <classname>Zend_XmlRpc_Response</classname>, или объект сообщения
- об ошибке <classname>Zend_XmlRpc_Server_Fault</classname>. Эти объекты имеют
- метод <code>__toString()</code>, который возвращает валидный XML-RPC
- ответ в формате XML, что позволяет выводить эти объекты
- через <code>echo</code>.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.conventions">
- <title>Соглашения</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> позволяет прикреплять функции и
- методы класса - т.н. доступные для диспетчеризации XML-RPC
- методы. С помощью <classname>Zend_Server_Reflection</classname> он проводит интроспекцию по
- всем прикрепленным методам, используя docblock'и функций и методов
- для установки текста справки и сигнатур методов.
- </para>
- <para>
- Не обязательно, чтобы типы в XML-RPC в точности соответствовали
- типам в PHP. Тем не менее, для наилучшего результата код пытается
- угадать наиболее подходящий тип, основываясь на значениях
- дескрипторов @param и @return. Некоторые типы в XML-RPC не имеют
- эквивалентов в PHP и должны указываться в PHPDoc. В их список
- входят:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- dateTime.iso8601 - дата в формате YYYYMMDDTHH:mm:ss
- </para>
- </listitem>
- <listitem><para>base64 - данные, закодированные по алгоритму base64</para></listitem>
- <listitem><para>struct - любой ассоциативный массив</para></listitem>
- </itemizedlist>
- <para>
- Пример того, как указывается XML-RPC тип
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Это пример функции
- *
- * @param base64 $val1 Закодированные в base64 данные
- * @param dateTime.iso8601 $val2 Дата в ISO-формате
- * @param struct $val3 Ассоциативный массив
- * @return struct
- */
- function myFunc($val1, $val2, $val3)
- {
- ]]></programlisting>
- <para>
- PhpDocumentor не проводит валидацию типов, определенных для
- параметров или возвращаемых значений, поэтому это не должно
- влиять на вашу документацию по API. Указание типов необходимо,
- если сервер проводит валидацию передаваемых методу параметров.
- </para>
- <para>
- Будет совершенно корректным с точки зрения синтаксиса определять
- набор возможных типов как для параметров, так и для возвращаемых
- значений; спецификация XML-RPC даже рекомендует, чтобы
- system.methodSignature возвращал массив всех
- возможных сигнатур метода (т.е. все возможные комбинации параметров
- и возвращаемых значений). Вы можете делать это в точности так же,
- как это обычно делается для PhpDocumentor - с использованием
- оператора '|':
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Это пример функции
- *
- * @param string|base64 $val1 Строка или закодированные в base64 данные
- * @param string|dateTime.iso8601 $val2 Строка или дата в ISO-формате
- * @param array|struct $val3 Обычный нумерованный массив или ассоциативный массив
- * @return boolean|struct
- */
- function myFunc($val1, $val2, $val3)
- {
- }
- ]]></programlisting>
- <para>
- Тем не менее, следует учесть, что обилие сигнатур может сбивать с
- толку разработчиков, использующих данный веб-сервис. Другими словами,
- следует стремится к тому, чтобы XML-RPC метод имел только одну
- сигнатуру.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.namespaces">
- <title>Использование пространств имен</title>
- <para>
- В XML-RPC есть такое понятие, как пространства имен. Они позволяют
- группировать методы посредством разделенных точкой
- имен пространств. Это позволяет предотвратить конфликты имен
- методов, предоставляемых разными классами. Например, обычно XML-RPC
- сервер предоставляет несколько методов в пространстве имен 'system':
- </para>
- <itemizedlist>
- <listitem><para>system.listMethods</para></listitem>
- <listitem><para>system.methodHelp</para></listitem>
- <listitem><para>system.methodSignature</para></listitem>
- </itemizedlist>
- <para>
- В нашем случае они соответствуют методам с теми же именами в
- <classname>Zend_XmlRpc_Server</classname>.
- </para>
- <para>
- Если необходимо добавить пространства имен для обслуживаемых
- методов, то просто укажите пространство имен в качестве параметра
- при вызове соответствующего метода для прикрепления функции или
- класса:
- </para>
- <programlisting language="php"><![CDATA[
- // Все открытые методы в My_Service_Class можно будет вызывать как
- // myservice.имя_метода
- $server->setClass('My_Service_Class', 'myservice');
- // Функцию 'somefunc' можно будет вызывать как funcs.somefunc
- $server->addFunction('somefunc', 'funcs');
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.xmlrpc.server.request">
- <title>Использование своих объектов запросов</title>
- <para>
- В большинстве случаев вы можете использовать включенный по умолчанию
- в <classname>Zend_XmlRpc_Server</classname> тип запроса –
- <classname>Zend_XmlRpc_Request_Http</classname>. Тем не
- менее, может потребоваться использование XML-RPC в окружениях
- CLI, GUI и т.п., журналирование приходящих запросов. Для этого вы
- можете создавать свои классы запросов, которые наследуют от
- <classname>Zend_XmlRpc_Request</classname>. Важно помнить при этом, что
- методы <code>getMethod()</code> и <code>getParams()</code>
- должны быть реализованы таким
- образом, чтобы XML-RPC сервер мог получить из них ту информацию,
- которая необходима для обработки запроса.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.response">
- <title>Использование своих объектов ответов</title>
- <para>
- Как и в случае объектов запросов, <classname>Zend_XmlRpc_Server</classname> может
- возвращать объекты других типов; по умолчанию возвращается
- объект <classname>Zend_XmlRpc_Response_Http</classname>, который отправляет соответствующий
- XML-RPC заголовок <code>Content-Type</code>. Целью создания своих
- типов ответов могут быть возможность журналирования
- ответов или отправки ответов обратно в STDOUT.
- </para>
- <para>
- Для того чтобы использовать свой класс ответа, вызывайте
- метод <code>Zend_XmlRpc_Server::setResponseClass()</code> до вызова
- метода <code>handle()</code>.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.fault">
- <title>Обработка исключений через сообщения об ошибке</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> отлавливает исключения, сгенерированные
- вызываемым методом и генерирует ответ с сообщением об ошибке сразу,
- как только исключение поймано. Однако по умолчанию сообщение и код
- исключения не используются в ответе с сообщением об ошибке. Это
- сделано намеренно для того, чтобы защитить ваш код, т.к. многие
- исключения могут выдавать информацию о коде приложения или
- среде выполнения, обычно предназначенные разработчику.
- </para>
- <para>
- Тем не менее, можно включать классы исключений в список разрешенных
- к отображению в ответах с сообщением об ошибке. Для этого
- используйте <code>Zend_XmlRpc_Server_Fault::attachFaultException()</code>
- для включения данного класса исключения в список разрешенных.
- </para>
- <programlisting language="php"><![CDATA[
- Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
- ]]></programlisting>
- <para>
- Если вы используете класс исключения, от которого наследуют другие
- исключения в проекте, то можете cразу включить все "семейство"
- исключений в список разрешенных. Исключения
- <classname>Zend_XmlRpc_Server_Exception</classname>
- всегда находится в списке разрешенных исключений для того, чтобы
- сообщать об отдельных внутренних ошибках (вызов несуществующего
- метода и т.д.).
- </para>
- <para>
- На любое исключение, не включенное в список разрешенных, будет
- генерироваться ответ с кодом ошибки '404' и сообщением 'Unknown
- error'.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.caching">
- <title>Кэширование определений сервера между запросами</title>
- <para>
- Прикрепление большого количества классов к экземпляру XML-RPC
- сервера может отнимать много ресурсов – каждый класс должен
- проверяться с использованием Reflection API (через
- <classname>Zend_Server_Reflection</classname>), который создает список всех возможных
- сигнатур методов для передачи классу сервера.
- </para>
- <para>
- Чтобы снизить ущерб производительности, можно использовать
- <classname>Zend_XmlRpc_Server_Cache</classname> для кэширования определений сервера между
- запросами. Если комбинировать его с <code>__autoload()</code>, то это может дать
- значительный прирост производительности.
- </para>
- <para>
- Пример использования:
- </para>
- <programlisting language="php"><![CDATA[
- function __autoload($class)
- {
- Zend_Loader::loadClass($class);
- }
- $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
- $server = new Zend_XmlRpc_Server();
- if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
- require_once 'My/Services/Glue.php';
- require_once 'My/Services/Paste.php';
- require_once 'My/Services/Tape.php';
- $server->setClass('My_Services_Glue', 'glue'); // пространство имен glue
- $server->setClass('My_Services_Paste', 'paste'); // пространство имен paste
- $server->setClass('My_Services_Tape', 'tape'); // пространство имен tape
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- echo $server->handle();
- ]]></programlisting>
- <para>
- В этом примере производится попытка получить определение сервера из
- файла xmlrpc.cache, находящегося в той же директории, что и скрипт.
- Если попытка не удалась, то загружаются нужные классы и
- прикрепляются к экземпляру сервера, затем создается новый файл кэша
- с определением сервера.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.use">
- <title>Примеры использования</title>
- <para>
- Здесь приведены несколько примеров использования, демонстрирующих полный
- набор возможностей, доступных разработчикам. Примеры
- построены на основе предоставленных ранее примеров.
- </para>
- <sect3 id="zend.xmlrpc.server.use.case1">
- <title>Основы использования</title>
- <para>
- В примере ниже прикрепляется функция в качестве
- доступного для диспетчеризации XML-RPC метода и обрабатываются
- входящие вызовы.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Возвращает сумму MD5 переданного значения
- *
- * @param string $value Value to md5sum
- * @return string MD5 sum of value
- */
- function md5Value($value)
- {
- return md5($value);
- }
- $server = new Zend_XmlRpc_Server();
- $server->addFunction('md5Value');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case2">
- <title>Прикрепление класса</title>
- <para>
- Пример ниже иллюстрирует прикрепление открытых методов класса
- в качестве доступных для диспетчеризации XML-RPC методов.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Comb.php';
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb');
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case3">
- <title>Прикрепление нескольких классов с использованием пространств имен</title>
- <para>
- Пример ниже демонстрирует прикрепление нескольких классов,
- каждый со своим пространством имен.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb', 'comb'); // методы, вызываемые как comb.*
- $server->setClass('Services_Brush', 'brush'); // методы, вызываемые как brush.*
- $server->setClass('Services_Pick', 'pick'); // методы, вызываемые как pick.*
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case4">
- <title>Указание исключений в качестве используемых для ответов с сообщением об ошибке</title>
- <para>
- Пример ниже позволяет любым наследующим от
- <code>Services_Exception</code>
- классам предоставлять свои коды и сообщения для подстановки в
- ответ с сообщением об ошибке.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Allow Services_Exceptions to report as fault responses
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb', 'comb'); // методы, вызываемые как comb.*
- $server->setClass('Services_Brush', 'brush'); // методы, вызываемые как brush.*
- $server->setClass('Services_Pick', 'pick'); // методы, вызываемые как pick.*
- echo $server->handle();
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case5">
- <title>Использование своих объектов запроса</title>
- <para>
- В примере ниже инстанцируется специальный объект запроса и
- передается серверу для обработки.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Request.php';
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Включение Services_Exceptions в список разрешенных исключений
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb', 'comb'); // методы, вызываемые как comb.*
- $server->setClass('Services_Brush', 'brush'); // методы, вызываемые как brush.*
- $server->setClass('Services_Pick', 'pick'); // методы, вызываемые как pick.*
- // Создание объекта запроса
- $request = new Services_Request();
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case6">
- <title>Использование своих объектов ответа</title>
- <para>
- Пример ниже демонстрирует указание специального класса ответа
- для возвращаемого ответа.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Services/Request.php';
- require_once 'Services/Response.php';
- require_once 'Services/Exception.php';
- require_once 'Services/Comb.php';
- require_once 'Services/Brush.php';
- require_once 'Services/Pick.php';
- // Включение Services_Exceptions в список разрешенных исключений
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb', 'comb'); // методы, вызываемые как comb.*
- $server->setClass('Services_Brush', 'brush'); // методы, вызываемые как brush.*
- $server->setClass('Services_Pick', 'pick'); // методы, вызываемые как pick.*
- // Создание объекта запроса
- $request = new Services_Request();
- // Установка другого класса ответа
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- <sect3 id="zend.xmlrpc.server.use.case7">
- <title>Кэширование определений сервера между запросами</title>
- <para>
- Пример ниже демонстрирует кэширование определений сервера между
- запросами.
- </para>
- <programlisting language="php"><![CDATA[
- // Указание файла кэша
- $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
- // Включение Services_Exceptions в список разрешенных исключений
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Попытка получить определение сервера из кэша
- if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
- $server->setClass('Services_Comb', 'comb'); // методы, вызываемые как comb.*
- $server->setClass('Services_Brush', 'brush'); // методы, вызываемые как brush.*
- $server->setClass('Services_Pick', 'pick'); // методы, вызываемые как pick.*
- // Сохранение в кэш
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- // Создание объекта запроса
- $request = new Services_Request();
- // Установка другого класса ответа
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|