| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- EN-Revision: 24249 -->
- <!-- Reviewed: no -->
- <sect1 id="zend.xmlrpc.server">
- <title>Zend_XmlRpc_Server</title>
- <sect2 id="zend.xmlrpc.server.introduction">
- <title>Einführung</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ist als vollständiger
- <acronym>XML-RPC</acronym> Server geplant, der den <ulink
- url="http://www.xmlrpc.com/spec">Spezifikationen auf www.xmlrpc.com</ulink> folgt.
- Des Weiteren implementiert er die Methode <command>system.multicall()</command>, welche
- dem Entwickler erlaubt, mehrere Anfragen aufzureihen.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.usage">
- <title>Grundlegende Benutzung</title>
- <para>
- Ein Beispiel der grundlegendsten Benutzung:
- </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>Server-Struktur</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ist aus einer Vielfalt von Komponenten
- zusammengesetzt, die vom Server selbst über Anfrage-, Antwort- und bis hin zu
- Fehler-Objekten reicht.
- </para>
- <para>
- Um den <classname>Zend_XmlRpc_Server</classname> zu erstellen, muss der Entwickler dem
- Server eine oder mehrere Klassen oder Funktionen durch die Methoden
- <methodname>setClass()</methodname> und <methodname>addFunction()</methodname>
- hinzufügen.
- </para>
- <para>
- Wenn dieses erstmal erledigt wurde, kann man entweder der Methode
- <methodname>Zend_XmlRpc_Server::handle()</methodname> ein
- <classname>Zend_XmlRpc_Request</classname>-Objekt übergeben oder es wird ein
- <classname>Zend_XmlRpc_Request_Http</classname> instanziert, falls keines angegeben
- wurde - die Anfrage wird also aus <filename>php://input</filename> geladen.
- </para>
- <para>
- <methodname>Zend_XmlRpc_Server::handle()</methodname> versucht daraufhin, den
- zuständigen Handler, der durch die angeforderte Methode bestimmt wird,
- auszuführen. Es wird entweder ein <classname>Zend_XmlRpc_Response</classname>-
- oder ein <classname>Zend_XmlRpc_Server_Fault</classname>-Objekt zurückgegeben.
- Beide Objekte besitzen eine Methode <methodname>__toString()</methodname>, die eine
- gültige <acronym>XML-RPC</acronym> Antwort im <acronym>XML</acronym>-Format zurückgibt,
- die direkt ausgegeben werden kann.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.anatomy">
- <title>Anatomie eines Webservices</title>
- <sect3 id="zend.xmlrpc.server.anatomy.general">
- <title>Generelle Annahmen</title>
- <para>
- Für eine maximale Performance ist es Notwendig eine einfache Bootstrap Datei für die
- Server Komponente zu verwenden. Der Verwendung von
- <classname>Zend_XmlRpc_Server</classname> innerhalb von <link
- linkend="zend.controller"><classname>Zend_Controller</classname></link> wird
- strengstens abgeraten um den Overhead zu vermeiden.
- </para>
- <para>
- Services ändern sich mit der Zeit, und während sich Webservices generell weniger
- intensiv ändern wie Code-native <acronym>APIs</acronym>, wird empfohlen den eigenen
- Service zu versionieren. Das legt den Grundstein für die Kompatibilität zu Clients
- welche eine ältere Version des eigenen Services verwenden und managt den
- Lebenszyklus des Services. Um das zu tun sollte eine Versionsnummer in die
- <acronym>URI</acronym> eingefügt werden. Es wird auch empfohlen den Namen des
- Remote Protokolls in der <acronym>URI</acronym> einzufügen um eine einfache
- Integration von zukünftigen Remote Technologien zu erlauben.
- http://myservice.ws/<emphasis>1.0/XMLRPC/</emphasis>.
- </para>
- </sect3>
- <sect3 id="zend.xmlrpc.server.anatomy.expose">
- <title>Was kann man freigeben?</title>
- <para>
- Meistens ist es nicht sensibel Business Objekte direkt freizugeben. Business
- Objekte sind normalerweise klein und werden häufig geändert, da die Änderung in
- diesem Layer der Anwendung sehr billig ist. Sobald Webservices bekanntgegeben und
- verwendet werden ist eine Änderung sehr hart. Andere Vorbehalte sind
- <acronym>I/O</acronym> und Latenz: die besten Aufrufe von Webservices sind jene die
- nicht stattfinden. Deswegen müssen Aufrufe zu Services grob körniger sein als die
- normale Business Logik selbst. Oft macht ein zusätzlicher Layer vor der Business
- Logik sinn. Dieser Layer wird manchmal als <ulink
- url="http://martinfowler.com/eaaCatalog/remoteFacade.html">Remote Facade</ulink>
- bezeichnet. Solch ein Service Layer fügt ein grob körniges Interface über der
- Business Logik hinzu und gruppiert langatmige Operationen zu kleineren.
- </para>
- </sect3>
- </sect2>
- <sect2 id="zend.xmlrpc.server.conventions">
- <title>Konventionen</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> ermöglicht es dem Entwickler, Funktionen und
- Methodenaufrufe als ausführbare <acronym>XML-RPC</acronym> Methoden anzufügen. Durch
- <classname>Zend_Server_Reflection</classname> wird die Überwachung aller angefügten
- Methoden - durch Nutzung der DocBlocks der Methoden und Funktionen
- werden deren Hilfstexte und Signaturen ermittelt - ermöglicht.
- </para>
- <para>
- <acronym>XML-RPC</acronym> Typen werden nicht zwingend 1:1 zu <acronym>PHP</acronym>
- Typen konvertiert. Dennoch wird versucht, einen passenden Typ, anhand der in
- @param- und @return-Zeilen enthaltenen Werte, zu ermitteln. Einige
- <acronym>XML-RPC</acronym> Typen besitzen jedoch kein direktes Äquivalent und sollten
- deshalb mittels <acronym>PHP</acronym>doc auf einen <acronym>XML-RPC</acronym> Typen
- hinweisen. Diese beinhalten:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis><property>dateTime.iso8601</property></emphasis>, ein String, der das
- Format <command>YYYYMMDDTHH:mm:ss</command> besitzt
- </para>
- </listitem>
- <listitem><para><emphasis>base64</emphasis>, base64-kodierte Daten</para></listitem>
- <listitem>
- <para><emphasis>struct</emphasis>, jegliches assoziatives Array</para>
- </listitem>
- </itemizedlist>
- <para>
- 'Anbei ein Beispiel für einen solchen Hinweis:
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Dies ist eine Beispielfunktion.
- *
- * @param base64 $val1 Base64-kodierte Daten
- * @param dateTime.iso8601 $val2 Ein ISO-Datum
- * @param struct $val3 ein assoziatives Array
- * @return struct
- */
- function myFunc($val1, $val2, $val3)
- {
- }
- ]]></programlisting>
- <para>
- PhpDocumentor validiert keine Typen, die in Parameter- oder
- Rückgabewerten angegeben sind, weshalb dies keinen Einfluss auf
- die <acronym>API</acronym> Dokumentation hat. Das Angeben der Hinweise ist notwendig,
- da der Server die, dem Methodenaufruf zugewiesenen, Parameter
- validiert.
- </para>
- <para>
- Es ist genauso gut möglich, mehrere Werte als Parameter oder für
- die Rückgabe anzugeben; die <acronym>XML-RPC</acronym> Spezifikation schlägt sogar
- vor, dass system.methodeSignatur ein Array, das alle möglichen
- Methodensignaturen (d.h. jegliche Kombination aus Parametern und
- Rückgabewerten) enthält, zurückgibt. Um dies zu erreichen, kann
- man, wie man es normalerweise auch beim PhpDocumentor auch tun würde,
- einfach den '|'-Operator nutzen.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Dies ist eine Beispiel-Funktion.
- *
- * @param string|base64 $val1 String oder base64-kodierte Daten
- * @param string|dateTime.iso8601 $val2 String oder ein ISO-Datum
- * @param array|struct $val3 Normal indiziertes oder assoziatives Array
- * @return boolean|struct
- */
- function myFunc($val1, $val2, $val3)
- {
- }
- ]]></programlisting>
- <note>
- <para>
- Wenn man viele Signaturen erlaubt kann dies zu Verwirrung bei Entwicklern führen,
- welche diese Services nutzen; um die Dinge einfach zu halten sollte eine
- <acronym>XML-RPC</acronym> Methode deshalb nur eine Signatur haben.
- </para>
- </note>
- </sect2>
- <sect2 id="zend.xmlrpc.server.namespaces">
- <title>Nutzen von Namensräumen</title>
- <para>
- <acronym>XML-RPC</acronym> besitzt ein Konzept für Namensräume; Grundlegend erlaubt es
- das Gruppieren von <acronym>XML-RPC</acronym> Methoden durch Punkt-separierte
- Namensräume. Dies hilft, Namenkollisionen zwischen Methoden, die durch verschiedene
- Klassen offeriert werden, zu verhindern. Beispielsweise kann der
- <acronym>XML-RPC</acronym> Server mehrere Methoden im 'system'-Namensraum nutzen:
- </para>
- <itemizedlist>
- <listitem><para>system.listMethods</para></listitem>
- <listitem><para>system.methodHelp</para></listitem>
- <listitem><para>system.methodSignature</para></listitem>
- </itemizedlist>
- <para>
- Intern werden die Methoden zu Methoden desselben Namens in der
- Klasse <classname>Zend_XmlRpc_Server</classname> umgeleitet.
- </para>
- <para>
- Um angebotenen Methoden Namensräume hinzuzufügen, muss man lediglich beim
- Hinzufügen der gewünschten Klasse oder Funktion einen Namensraum angeben:
- </para>
- <programlisting language="php"><![CDATA[
- // Alle öffentlichten Methoden in My_Service_Class sind als
- // myservice.METHODNAME verfügbar
- $server->setClass('My_Service_Class', 'myservice');
- // Funktion 'somefunc' ist als funcs.somefunc ansprechbar.
- $server->addFunction('somefunc', 'funcs');
- ]]></programlisting>
- </sect2>
- <sect2 id="zend.xmlrpc.server.request">
- <title>Eigene Request-Objekte</title>
- <para>
- Die meiste Zeit wird man einfach den Standard-Anfragetyp
- <classname>Zend_XmlRpc_Request_Http</classname>, welcher im
- <classname>Zend_XmlRpc_Server</classname> enthalten ist, nutzen. Jedoch gibt es
- gelegentlich Fälle, in denen <acronym>XML-RPC</acronym> über die Kommandozeile
- (<acronym>CLI</acronym>), ein grafisches Benutzerinterface (<acronym>GUI</acronym>),
- eine andere Umgebung oder beim Protokollieren von ankommenden Anfragen erreichbar sein
- muss. Um dies zu bewerkstelligen, muss man ein eigenes Anfrage-Objekt kreieren, das
- <classname>Zend_XmlRpc_Request</classname> erweitert. Die wichtigste Sache, die man
- sich merken muss, ist sicherzustellen, dass die Methoden
- <methodname>getMethod()</methodname> und <methodname>getParams()</methodname>
- implementiert sind, so dass der <acronym>XML-RPC</acronym> Server Informationen erhält,
- die er für das Abfertigen einer Anfrage benötigt.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.response">
- <title>Eigene Antwort-Objekte</title>
- <para>
- Ähnlich wie bei den Anfrage-Objekten, kann der <classname>Zend_XmlRpc_Server</classname>
- auch eigene Antwortobjekte ausliefern; standardmäßig ist dies ein
- <classname>Zend_XmlRpc_Response_Http-Objekt</classname>, das einen passenden
- Content-Type <acronym>HTTP</acronym>-Header sendet, der für <acronym>XML-RPC</acronym>
- genutzt wird. Mögliche Nutzungen eines eigenen Objekts sind z.B. das Protokollieren von
- Antworten oder das Senden der Antworten zu <constant>STDOUT</constant>.
- </para>
- <para>
- Um eine eigene Antwortklasse zu nutzen, muss
- <methodname>Zend_XmlRpc_Server::setResponseClass()</methodname> vor dem Aufruf von
- <methodname>handle()</methodname> aufgerufen werden.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.fault">
- <title>Verarbeiten von Exceptions durch Fehler</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> fängt die, durch eine ausgeführte Methode
- erzeugten, Exceptions and generiert daraus einen <acronym>XML-RPC</acronym> Fehler als
- Antwort, wenn eine Exception gefangen wurde. Normalerweise werden die
- Exceptionnachrichten und -codes nicht in der Fehler-Antwort genutzt. Dies ist eine
- gewollte Entscheidung um den Code zu schützen; viele Exceptions entblößen mehr
- Informationen über den Code oder die Umgebung als der Entwickler
- wünscht (ein Paradebeispiel beinhaltet Datenbankabstraktion- oder
- die Zugriffsschichten-Exceptions).
- </para>
- <para>
- Exception-Klassen können jedoch anhand einer Weißliste (Whitelist) als
- Fehler-Antworten zurückgegeben werden. Dazu muss man lediglich die gewünschte
- Exception mittels
- <methodname>Zend_XmlRpc_Server_Fault::attachFaultException()</methodname> zur
- Weißliste hinzufügen:
- </para>
- <programlisting language="php"><![CDATA[
- Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
- ]]></programlisting>
- <para>
- Abgeleitete Exceptions lassen sich als ganze Familie von Exceptions
- hinzufügen, indem man deren Basisklasse angibt.
- <classname>Zend_XmlRpc_Server_Exception</classname>'s sind immer auf der Weißliste zu
- finden, da sie spezielle Serverfehler berichten (undefinierte Methoden, etc.).
- </para>
- <para>
- Jede Exception, die nicht auf der Weißliste zu finden ist, generiert
- eine Antwort mit dem '404' Code und der Nachricht 'Unknown error'.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.caching">
- <title>Zwischenspeichern von Serverdefinitionen zwischen den Anfragen</title>
- <para>
- Das Hinzufügen einer Vielzahl von Klassen zu einer <acronym>XML-RPC</acronym> Server
- Instanz kann zu einem großen Ressourcenverbrauch führen; jede Klasse muss via Reflection
- <acronym>API</acronym> (<classname>Zend_Server_Reflection</classname>) inspiziert
- werden, welche eine Liste von allen möglichen Signaturen, die der Server verwenden kann,
- zurückgibt.
- </para>
- <para>
- Um die Einbußen zu reduzieren, kann <classname>Zend_XmlRpc_Server_Cache</classname>
- genutzt werden, welche die Serverdefinitionen zwischen den Anfragen zwischenspeichert.
- Wenn dies mit <methodname>__autoload()</methodname> kombiniert wird, kann es zu einem
- großen Geschwindigkeitsschub kommen.
- </para>
- <para>
- Ein Beispiel folgt:
- </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. Namensraum
- $server->setClass('My_Services_Paste', 'paste'); // paste. Namensraum
- $server->setClass('My_Services_Tape', 'tape'); // tape. Namensraum
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- echo $server->handle();
- ]]></programlisting>
- <para>
- Obiges Beispiel zeigt, wie der Server versucht, eine Definition
- aus der Datei <property>xmlrpc.cache</property>, welches sich im selben Ordner wie das
- Skript befindet, zu laden. Wenn dies nicht erfolgreich ist,
- lädt es die Server-Klassen, die es benötigt, und fügt sie zum
- Server hinzu. Danach wird versucht, die Cache-Datei mit der
- Serverdefinition zu erstellen.
- </para>
- </sect2>
- <sect2 id="zend.xmlrpc.server.use">
- <title>Nutzungsbeispiele</title>
- <para>
- Unten finden sich etliche Beispiele für eine Nutzung, die das
- gesamte Spektrum der verfügbaren Optionen für den Entwickler darstellen.
- These Beispiele bauen immer auf den vorangegangenen Beispielen auf.
- </para>
- <example id="zend.xmlrpc.server.use.attach-function">
- <title>Grundlegende Benutzung</title>
- <para>
- Folgendes Beispiel fügt eine Funktion als ausführbare
- <acronym>XML-RPC</acronym> Methode hinzu und verarbeitet eingehende Aufrufe.
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Gibt die MD5-Summe eines Strings zurück.
- *
- * @param string $value Wert aus dem die MD5-Summe errechnet wird
- * @return string MD5-Summe des Werts
- */
- function md5Value($value)
- {
- return md5($value);
- }
- $server = new Zend_XmlRpc_Server();
- $server->addFunction('md5Value');
- echo $server->handle();
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.attach-class">
- <title>Hinzufügen einer Klasse</title>
- <para>
- Das nächste Beispiel illustriert, wie man die öffentlichen Methoden
- eienr Klasse als ausführbare <acronym>XML-RPC</acronym> Methoden hinzufügt.
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_Comb');
- echo $server->handle();
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.attach-class-with-arguments">
- <title>Hinzufügen einer Klasse mit Argumenten</title>
- <para>
- Das folgende Beispiel zeigt wie öffentliche Methoden einer Klasse hinzugefügt werden
- und an deren Methoden Argumente übergeben werden können. Das kann verwendet werden
- um spezielle Standardwerte zu spezifizieren wenn Serviceklassen registriert werden.
- </para>
- <programlisting language="php"><![CDATA[
- class Services_PricingService
- {
- /**
- * Calculate current price of product with $productId
- *
- * @param ProductRepository $productRepository
- * @param PurchaseRepository $purchaseRepository
- * @param integer $productId
- */
- public function calculate(ProductRepository $productRepository,
- PurchaseRepository $purchaseRepository,
- $productId)
- {
- ...
- }
- }
- $server = new Zend_XmlRpc_Server();
- $server->setClass('Services_PricingService',
- 'pricing',
- new ProductRepository(),
- new PurchaseRepository());
- ]]></programlisting>
- <para>
- Die Argumente welche an <methodname>setClass()</methodname> während der
- Erstellungszeit des Servers übergeben werden, werden dem Methodenaufruf
- <command>pricing.calculate()</command> injiziert, wenn er aufgerufen wird. Im obigen
- Beispiel wird vom Client nur das Argument <varname>$purchaseId</varname> erwartet.
- </para>
- </example>
- <example id="zend.xmlrpc.server.use.attach-class-with-arguments-constructor">
- <title>Argumente nur dem Constructor übergeben</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> erlaubt es die Übergabe von Argumenten nur
- für den Constructor zu limitieren. Das kann für Dependency Injection beim
- Constructor verwendet werden. Um die Injektion auf Constructoren zu begrenzen muss
- <methodname>sendArgumentsToAllMethods</methodname> aufgerufen und
- <constant>FALSE</constant> als Argument übergeben werden. Dies deaktiviert das
- Standardverhalten mit dem alle Argumente in die entfernte Methode injiziert werden.
- Im nächsten Beispiel werden die Instanzen von
- <classname>ProductRepository</classname> und
- <classname>PurchaseRepository</classname> nur in dem Constructor von
- <classname>Services_PricingService2</classname> injiziert.
- </para>
- <programlisting language="php"><![CDATA[
- class Services_PricingService2
- {
- /**
- * @param ProductRepository $productRepository
- * @param PurchaseRepository $purchaseRepository
- */
- public function __construct(ProductRepository $productRepository,
- PurchaseRepository $purchaseRepository)
- {
- ...
- }
- /**
- * Calculate current price of product with $productId
- *
- * @param integer $productId
- * @return double
- */
- public function calculate($productId)
- {
- ...
- }
- }
- $server = new Zend_XmlRpc_Server();
- $server->sendArgumentsToAllMethods(false);
- $server->setClass('Services_PricingService2',
- 'pricing',
- new ProductRepository(),
- new PurchaseRepository());
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.attach-instance">
- <title>Die Instanz einer Klasse anhängen</title>
- <para>
- <methodname>setClass()</methodname> erlaubt es ein vorher instanziertes Objekt beim
- Server zu registrieren. Man muss nur die Instanz statt dem Namen der Klasse
- übergeben. Natürlich ist die Übergabe von Argumenten an den Constructor bei vorher
- instanzierten Objekten nicht möglich.
- </para>
- </example>
- <example id="zend.xmlrpc.server.use.attach-several-classes-namespaces">
- <title>Mehrere Klassen unter der Nutzung von Namensräumen hinzufügen</title>
- <para>
- Das nächste Beispiel zeigt, wie man mehrer Klassen mit ihren eigenen
- Namensräumen hinzufügt.
- </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();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- echo $server->handle();
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.exception-faults">
- <title>Bestimmen von Exceptions als gültige Fehler-Antwort</title>
- <para>
- Im nächsten Beispiel wird gezeigt, wie man jede Exception, die von
- <classname>Services_Exception</classname> abgeleitet wurde, als Fehler-Antwort
- nutzen kann, dessen Nachricht und Code erhalten bleibt.
- </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';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- echo $server->handle();
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.custom-request-object">
- <title>Anpassen eigener Anfrage und Antwort Objekte</title>
- <para>
- Einige Anwendungsfälle verlangen die Verwendung eines eigenen Request Objektes.
- Zum Beispiel ist <acronym>XML/RPC</acronym> nicht an <acronym>HTTP</acronym> als
- Übertragungsprotokoll gebunden. Es ist möglich auch andere Übertragungsprotokolle
- wie <acronym>SSH</acronym> oder Telnet zu verwenden um Anfrage und Antwort Daten
- über den Draht zu senden. Ein anderer Anwendungsfall ist die Authentifizierung
- und Authorisierung. Im Falle eines anderen Übertragungsprotokolls muss die
- Implementation geändert werden damit Anfrage Daten gelesen werden können.
- </para>
- <para>
- Im folgenden Beispiel wird ein eigenes Anfrage-Objekt instanziert
- und durch den Server verarbeitet.
- </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 dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- echo $server->handle($request);
- ]]></programlisting>
- </example>
- <example id="zend.xmlrpc.server.use.custom-response-object">
- <title>Eine eigene Antwort Klasse spezifizieren</title>
- <para>
- Das nachstehende Beispiel zeigt, wie man eine eigene Antwort-Klasse
- als zurückgegebene Antwort für den Server setzt.
- </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 dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- // Nutzen eigener Antwort-Klasse
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </example>
- </sect2>
- <sect2 id="zend.xmlrpc.server.performance">
- <title>Performance Optimierung</title>
- <example id="zend.xmlrpc.server.performance.caching">
- <title>Zwischenspeichern von Serverdefinition zwischen den Anfragen</title>
- <para>
- Dieses Beispiel zeigt, wie man Serverdefinitionen zwischen verschiedenen
- Anfragen zwischenspeichern kann.
- </para>
- <programlisting language="php"><![CDATA[
- // Definieren einer Cache-Datei
- $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
- // Services_Exceptions dürfen als Fehler-Antwort genutzt werden
- Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
- $server = new Zend_XmlRpc_Server();
- // Versucht die Serverdefinition aus dem Cache zu laden
- if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
- // Methoden werden als comb.* aufgerufen
- $server->setClass('Services_Comb', 'comb');
- // Methoden werden als brush.* aufgerufen
- $server->setClass('Services_Brush', 'brush');
- // Methoden werden als pick.* aufgerufen
- $server->setClass('Services_Pick', 'pick');
- // Speichern des Caches
- Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
- }
- // Ein neues Anfrage-Objekt wird erstellt
- $request = new Services_Request();
- // Nutzen eigener Antwort-Klasse
- $server->setResponseClass('Services_Response');
- echo $server->handle($request);
- ]]></programlisting>
- </example>
- <note>
- <para>
- Die Datei des Server Caches sollte ausserhalb des Document Roots platziert
- werden.
- </para>
- </note>
- <example id="zend.xmlrpc.server.performance.xmlgen">
- <title>Optimizing XML generation</title>
- <para>
- <classname>Zend_XmlRpc_Server</classname> verwendet
- <classname>DOMDocument</classname> der <acronym>PHP</acronym> Erweiterung
- <emphasis>ext/dom</emphasis> um seine <acronym>XML</acronym> Ausgaben zu erstellen.
- Wärend <emphasis>ext/dom</emphasis> auf vielen Hosts vorhanden ist, ist es nicht
- wirklich das schnellste. Benchmarks haben gezeigt das
- <classname>XmlWriter</classname> von <emphasis>ext/xmlwriter</emphasis> schneller
- ist.
- </para>
- <para>
- Wenn <emphasis>ext/xmlwriter</emphasis> auf dem eigenen Host vorhanden ist, kann ein
- <classname>XmlWriter</classname>-basierter Generator ausgewählt werden um die
- Performance Unterschiede auszunutzen.
- </para>
- <programlisting language="php"><![CDATA[
- require_once 'Zend/XmlRpc/Server.php';
- require_once 'Zend/XmlRpc/Generator/XmlWriter.php';
- Zend_XmlRpc_Value::setGenerator(new Zend_XmlRpc_Generator_XmlWriter());
- $server = new Zend_XmlRpc_Server();
- ...
- ]]></programlisting>
- </example>
- <note>
- <title>Die eigene Anwendung benchmarken</title>
- <para>
- Performance wird durch eine Vielzahl an Parametern und Benchmarks ermittelt
- welche nur für den speziellen Testfall angewendet werden. Unterschiede basieren
- auf der <acronym>PHP</acronym> Version, installierten Erweiterungen, dem Webserver
- und dem Betriebssystem um nur einige zu nennen. Man sollte darauf achten das man die
- eigene Anwendung selbst benchmarkt und anschließend auswählt welchen Generator
- man verwendet, aber basierend auf <emphasis>eigenen</emphasis> Zahlen.
- </para>
- </note>
- <note>
- <title>Den eigenen Client benchmarken</title>
- <para>
- Diese Optimierung macht auch für die Client Seite Sinn. Man muss den
- alternativen <acronym>XML</acronym> Generator nur auswählen bevor man irgendeine
- Arbeit mit <classname>Zend_XmlRpc_Client</classname> durchführt.
- </para>
- </note>
- </sect2>
- </sect1>
|