[GENERIC] Zend_Translate:
[zend.git] / documentation / manual / en / module_specs / Zend_XmlRpc_Server.xml
blobca5045ccdfda089db2f5ee22eb674760bd489232
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.xmlrpc.server">
4     <title>Zend_XmlRpc_Server</title>
6     <sect2 id="zend.xmlrpc.server.introduction">
7         <title>Introduction</title>
9         <para>
10             <classname>Zend_XmlRpc_Server</classname> is intended as a fully-featured
11             <acronym>XML-RPC</acronym> server, following <ulink url="http://www.xmlrpc.com/spec">the
12                 specifications outlined at www.xmlrpc.com</ulink>. Additionally, it implements the
13             <command>system.multicall()</command> method, allowing boxcarring of requests.
14         </para>
15     </sect2>
17     <sect2 id="zend.xmlrpc.server.usage">
18         <title>Basic Usage</title>
20         <para>
21             An example of the most basic use case:
22         </para>
24         <programlisting language="php"><![CDATA[
25 $server = new Zend_XmlRpc_Server();
26 $server->setClass('My_Service_Class');
27 echo $server->handle();
28 ]]></programlisting>
29     </sect2>
31     <sect2 id="zend.xmlrpc.server.structure">
32         <title>Server Structure</title>
34         <para>
35             <classname>Zend_XmlRpc_Server</classname> is composed of a variety of components,
36             ranging from the server itself to request, response, and fault objects.
37         </para>
39         <para>
40             To bootstrap <classname>Zend_XmlRpc_Server</classname>, the developer must attach one or
41             more classes or functions to the server, via the
42             <methodname>setClass()</methodname> and <methodname>addFunction()</methodname> methods.
43         </para>
45         <para>
46             Once done, you may either pass a <classname>Zend_XmlRpc_Request</classname>
47             object to <methodname>Zend_XmlRpc_Server::handle()</methodname>, or it will
48             instantiate a <classname>Zend_XmlRpc_Request_Http</classname> object if none
49             is provided -- thus grabbing the request from
50             <filename>php://input</filename>.
51         </para>
53         <para>
54             <methodname>Zend_XmlRpc_Server::handle()</methodname> then attempts to
55             dispatch to the appropriate handler based on the method
56             requested. It then returns either a
57             <classname>Zend_XmlRpc_Response</classname>-based object or a
58             <classname>Zend_XmlRpc_Server_Fault</classname>object. These objects both have
59             <methodname>__toString()</methodname> methods that create valid
60             <acronym>XML-RPC</acronym> <acronym>XML</acronym> responses, allowing them to be
61             directly echoed.
62         </para>
63     </sect2>
65     <sect2 id="zend.xmlrpc.server.anatomy">
66         <title>Anatomy of a webservice</title>
68         <sect3 id="zend.xmlrpc.server.anatomy.general">
69             <title>General considerations</title>
71             <para>
72                 For maximum performance it is recommended to use a simple
73                 bootstrap file for the server component. Using
74                 <classname>Zend_XmlRpc_Server</classname> inside a
75                 <link linkend="zend.controller"><classname>Zend_Controller</classname></link>
76                 is strongly discouraged to avoid the overhead.
77             </para>
79             <para>
80                 Services change over time and while webservices are generally
81                 less change intense as code-native <acronym>APIs</acronym>, it
82                 is recommended to version your service. Do so to lay grounds to
83                 provide compatibility for clients using older versions of your
84                 service and manage your service lifecycle including deprecation
85                 timeframes.To do so just include a version number into your
86                 <acronym>URI</acronym>. It is also recommended to include the
87                 remote protocol name in the <acronym>URI</acronym> to allow easy
88                 integration of upcoming remoting technologies.
89                 http://myservice.ws/<emphasis>1.0/XMLRPC/</emphasis>.
90             </para>
91         </sect3>
93         <sect3 id="zend.xmlrpc.server.anatomy.expose">
94             <title>What to expose?</title>
96             <para>
97                 Most of the time it is not sensible to expose business objects
98                 directly. Business objects are usually small and under heavy
99                 change, because change is cheap in this layer of your
100                 application. Once deployed and adopted, web services are hard to
101                 change. Another concern is <acronym>I/O</acronym> and latency:
102                 the best webservice calls are those not happening. Therefore
103                 service calls need to be more coarse-grained than usual business
104                 logic is. Often an additional layer in front of your business
105                 objects makes sense. This layer is sometimes referred to as <ulink
106                     url="http://martinfowler.com/eaaCatalog/remoteFacade.html">Remote
107                     Facade</ulink>.
108                 Such a service layer adds a coarse grained interface on top of
109                 your business logic and groups verbose operations into smaller
110                 ones.
111             </para>
112         </sect3>
113     </sect2>
115     <sect2 id="zend.xmlrpc.server.conventions">
116         <title>Conventions</title>
118         <para>
119             <classname>Zend_XmlRpc_Server</classname> allows the developer to attach functions and
120             class method calls as dispatchable <acronym>XML-RPC</acronym> methods. Via
121             <classname>Zend_Server_Reflection</classname>, it does introspection on all attached
122             methods, using the function and method docblocks to determine the
123             method help text and method signatures.
124         </para>
126         <para>
127             <acronym>XML-RPC</acronym> types do not necessarily map one-to-one to
128             <acronym>PHP</acronym> types. However, the code will do its best to guess the
129             appropriate type based on the values listed in @param and @return lines. Some
130             <acronym>XML-RPC</acronym> types have no immediate <acronym>PHP</acronym> equivalent,
131             however, and should be hinted using the <acronym>XML-RPC</acronym> type in the PHPDoc.
132             These include:
133         </para>
135         <itemizedlist>
136             <listitem>
137                 <para>
138                     <emphasis><property>dateTime.iso8601</property></emphasis>, a string formatted
139                     as '<command>YYYYMMDDTHH:mm:ss</command>'
140                 </para>
141             </listitem>
143             <listitem><para><emphasis>base64</emphasis>, base64 encoded data</para></listitem>
145             <listitem><para><emphasis>struct</emphasis>, any associative array</para></listitem>
146         </itemizedlist>
148         <para>
149             An example of how to hint follows:
150         </para>
152         <programlisting language="php"><![CDATA[
154 * This is a sample function
156 * @param base64 $val1 Base64-encoded data
157 * @param dateTime.iso8601 $val2 An ISO date
158 * @param struct $val3 An associative array
159 * @return struct
161 function myFunc($val1, $val2, $val3)
164 ]]></programlisting>
166         <para>
167             PhpDocumentor does no validation of the types specified for params
168             or return values, so this will have no impact on your <acronym>API</acronym>
169             documentation. Providing the hinting is necessary, however, when the
170             server is validating the parameters provided to the method call.
171         </para>
173         <para>
174             It is perfectly valid to specify multiple types for both params and
175             return values; the <acronym>XML-RPC</acronym> specification even suggests that
176             system.methodSignature should return an array of all possible method
177             signatures (i.e., all possible combinations of param and return
178             values). You may do so just as you normally would with
179             PhpDocumentor, using the '|' operator:
180         </para>
182         <programlisting language="php"><![CDATA[
184 * This is a sample function
186 * @param string|base64 $val1 String or base64-encoded data
187 * @param string|dateTime.iso8601 $val2 String or an ISO date
188 * @param array|struct $val3 Normal indexed array or an associative array
189 * @return boolean|struct
191 function myFunc($val1, $val2, $val3)
194 ]]></programlisting>
196         <note>
197             <para>
198                 Allowing multiple signatures can lead to confusion for developers
199                 using the services; to keep things simple, a <acronym>XML-RPC</acronym>
200                 service method should only have a single signature.
201             </para>
202         </note>
203     </sect2>
205     <sect2 id="zend.xmlrpc.server.namespaces">
206         <title>Utilizing Namespaces</title>
208         <para>
209             <acronym>XML-RPC</acronym> has a concept of namespacing; basically, it allows grouping
210             <acronym>XML-RPC</acronym> methods by dot-delimited namespaces. This helps prevent
211             naming collisions between methods served by different classes. As an
212             example, the <acronym>XML-RPC</acronym> server is expected to server several methods in
213             the 'system' namespace:
214         </para>
216         <itemizedlist>
217             <listitem><para>system.listMethods</para></listitem>
218             <listitem><para>system.methodHelp</para></listitem>
219             <listitem><para>system.methodSignature</para></listitem>
220         </itemizedlist>
222         <para>
223             Internally, these map to the methods of the same name in
224             <classname>Zend_XmlRpc_Server</classname>.
225         </para>
227         <para>
228             If you want to add namespaces to the methods you serve, simply
229             provide a namespace to the appropriate method when attaching a
230             function or class:
231         </para>
233         <programlisting language="php"><![CDATA[
234 // All public methods in My_Service_Class will be accessible as
235 // myservice.METHODNAME
236 $server->setClass('My_Service_Class', 'myservice');
238 // Function 'somefunc' will be accessible as funcs.somefunc
239 $server->addFunction('somefunc', 'funcs');
240 ]]></programlisting>
241     </sect2>
243     <sect2 id="zend.xmlrpc.server.request">
244         <title>Custom Request Objects</title>
246         <para>
247             Most of the time, you'll simply use the default request type included with
248             <classname>Zend_XmlRpc_Server</classname>,
249             <classname>Zend_XmlRpc_Request_Http</classname>. However, there may be times when you
250             need <acronym>XML-RPC</acronym> to be available via the <acronym>CLI</acronym>, a
251             <acronym>GUI</acronym>, or other environment, or want to log incoming requests. To do
252             so, you may create a custom request object that extends
253             <classname>Zend_XmlRpc_Request</classname>. The most important thing to remember is to
254             ensure that the <methodname>getMethod()</methodname> and
255             <methodname>getParams()</methodname> methods are implemented so that the
256             <acronym>XML-RPC</acronym> server can retrieve that information in order to dispatch the
257             request.
258         </para>
259     </sect2>
261     <sect2 id="zend.xmlrpc.server.response">
262         <title>Custom Responses</title>
264         <para>
265             Similar to request objects, <classname>Zend_XmlRpc_Server</classname> can return custom
266             response objects; by default, a <classname>Zend_XmlRpc_Response_Http</classname> object
267             is returned, which sends an appropriate Content-Type <acronym>HTTP</acronym> header for
268             use with <acronym>XML-RPC</acronym>. Possible uses of a custom object would be to log
269             responses, or to send responses back to <constant>STDOUT</constant>.
270         </para>
272         <para>
273             To use a custom response class, use
274             <methodname>Zend_XmlRpc_Server::setResponseClass()</methodname> prior to calling
275             <methodname>handle()</methodname>.
276         </para>
277     </sect2>
279     <sect2 id="zend.xmlrpc.server.fault">
280         <title>Handling Exceptions via Faults</title>
282         <para>
283             <classname>Zend_XmlRpc_Server</classname> catches Exceptions generated by a dispatched
284             method, and generates an <acronym>XML-RPC</acronym> fault response when such an
285             exception is caught. By default, however, the exception messages and
286             codes are not used in a fault response. This is an intentional
287             decision to protect your code; many exceptions expose more
288             information about the code or environment than a developer would
289             necessarily intend (a prime example includes database abstraction or
290             access layer exceptions).
291         </para>
293         <para>
294             Exception classes can be whitelisted to be used as fault responses,
295             however. To do so, simply utilize
296             <methodname>Zend_XmlRpc_Server_Fault::attachFaultException()</methodname> to pass an
297             exception class to whitelist:
298         </para>
300         <programlisting language="php"><![CDATA[
301 Zend_XmlRpc_Server_Fault::attachFaultException('My_Project_Exception');
302 ]]></programlisting>
304         <para>
305             If you utilize an exception class that your other project exceptions
306             inherit, you can then whitelist a whole family of exceptions at a
307             time. <classname>Zend_XmlRpc_Server_Exception</classname>s are always whitelisted, to
308             allow reporting specific internal errors (undefined methods, etc.).
309         </para>
311         <para>
312             Any exception not specifically whitelisted will generate a fault
313             response with a code of '404' and a message of 'Unknown error'.
314         </para>
315     </sect2>
317     <sect2 id="zend.xmlrpc.server.caching">
318         <title>Caching Server Definitions Between Requests</title>
320         <para>
321             Attaching many classes to an <acronym>XML-RPC</acronym> server instance can utilize a
322             lot of resources; each class must introspect using the Reflection
323             <acronym>API</acronym> (via <classname>Zend_Server_Reflection</classname>), which in
324             turn generates a list of all possible method signatures to provide to the server class.
325         </para>
327         <para>
328             To reduce this performance hit somewhat, <classname>Zend_XmlRpc_Server_Cache</classname>
329             can be used to cache the server definition between requests. When
330             combined with <methodname>__autoload()</methodname>, this can greatly increase
331             performance.
332         </para>
334         <para>
335             An sample usage follows:
336         </para>
338         <programlisting language="php"><![CDATA[
339 function __autoload($class)
341     Zend_Loader::loadClass($class);
344 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
345 $server = new Zend_XmlRpc_Server();
347 if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
348     require_once 'My/Services/Glue.php';
349     require_once 'My/Services/Paste.php';
350     require_once 'My/Services/Tape.php';
352     $server->setClass('My_Services_Glue', 'glue');   // glue. namespace
353     $server->setClass('My_Services_Paste', 'paste'); // paste. namespace
354     $server->setClass('My_Services_Tape', 'tape');   // tape. namespace
356     Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
359 echo $server->handle();
360 ]]></programlisting>
362         <para>
363             The above example attempts to retrieve a server definition from
364             <property>xmlrpc.cache</property> in the same directory as the script. If unsuccessful,
365             it loads the service classes it needs, attaches them to the server
366             instance, and then attempts to create a new cache file with the
367             server definition.
368         </para>
369     </sect2>
371     <sect2 id="zend.xmlrpc.server.use">
372         <title>Usage Examples</title>
374         <para>
375             Below are several usage examples, showing the full spectrum of
376             options available to developers. Usage examples will each build
377             on the previous example provided.
378         </para>
380         <example id="zend.xmlrpc.server.use.attach-function">
381             <title>Basic Usage</title>
383             <para>
384                 The example below attaches a function as a dispatchable <acronym>XML-RPC</acronym>
385                 method and handles incoming calls.
386             </para>
388             <programlisting language="php"><![CDATA[
390  * Return the MD5 sum of a value
392  * @param string $value Value to md5sum
393  * @return string MD5 sum of value
394  */
395 function md5Value($value)
397     return md5($value);
400 $server = new Zend_XmlRpc_Server();
401 $server->addFunction('md5Value');
402 echo $server->handle();
403 ]]></programlisting>
404         </example>
406         <example id="zend.xmlrpc.server.use.attach-class">
407             <title>Attaching a class</title>
409             <para>
410                 The example below illustrates attaching a class' public methods
411                 as dispatchable <acronym>XML-RPC</acronym> methods.
412             </para>
414             <programlisting language="php"><![CDATA[
415 require_once 'Services/Comb.php';
417 $server = new Zend_XmlRpc_Server();
418 $server->setClass('Services_Comb');
419 echo $server->handle();
420 ]]></programlisting>
421         </example>
423         <example id="zend.xmlrpc.server.use.attach-class-with-arguments">
424             <title>Attaching a class with arguments</title>
426             <para>
427                 The following example illustrates how to attach a class' public
428                 methods and passing arguments to its methods. This can be used to specify certain
429                 defaults when registering service classes.
430             </para>
432             <programlisting language="php"><![CDATA[
433 class Services_PricingService
435     /**
436      * Calculate current price of product with $productId
437      *
438      * @param ProductRepository $productRepository
439      * @param PurchaseRepository $purchaseRepository
440      * @param integer $productId
441      */
442     public function calculate(ProductRepository $productRepository,
443                               PurchaseRepository $purchaseRepository,
444                               $productId)
445     {
446         ...
447     }
450 $server = new Zend_XmlRpc_Server();
451 $server->setClass('Services_PricingService',
452                   'pricing',
453                   new ProductRepository(),
454                   new PurchaseRepository());
455 ]]></programlisting>
457             <para>
458                 The arguments passed at <methodname>setClass()</methodname> at server construction
459                 time are injected into the method call <command>pricing.calculate()</command> on
460                 remote invokation. In the example above, only the argument <code>$purchaseId</code>
461                 is expected from the client.
462             </para>
463         </example>
465         <example id="zend.xmlrpc.server.use.attach-class-with-arguments-constructor">
466             <title>Passing arguments only to constructor</title>
468             <para>
469                 <classname>Zend_XmlRpc_Server</classname> allows to restrict argument passing to
470                 constructors only. This can be used for constructor dependency injection.
471                 To limit injection to constructors, call
472                 <methodname>sendArgumentsToAllMethods</methodname> and pass
473                 <constant>FALSE</constant> as an argument. This disables the default behavior of all
474                 arguments being injected into the remote method. In the example below the instance
475                 of <classname>ProductRepository</classname> and
476                 <classname>PurchaseRepository</classname> is only injected into the constructor of
477                 <classname>Services_PricingService2</classname>.
478             </para>
480             <programlisting language="php"><![CDATA[
481 class Services_PricingService2
483     /**
484      * @param ProductRepository $productRepository
485      * @param PurchaseRepository $purchaseRepository
486      */
487     public function __construct(ProductRepository $productRepository,
488                                 PurchaseRepository $purchaseRepository)
489     {
490         ...
491     }
493     /**
494      * Calculate current price of product with $productId
495      *
496      * @param integer $productId
497      * @return double
498      */
499     public function calculate($productId)
500     {
501         ...
502     }
505 $server = new Zend_XmlRpc_Server();
506 $server->sendArgumentsToAllMethods(false);
507 $server->setClass('Services_PricingService2',
508                   'pricing',
509                   new ProductRepository(),
510                   new PurchaseRepository());
511 ]]></programlisting>
512         </example>
514         <example id="zend.xmlrpc.server.use.attach-instance">
515             <title>Attaching a class instance</title>
517             <para>
518                 <methodname>setClass()</methodname> allows to register a previously instantiated
519                 object at the server. Just pass an instance instead of the class name. Obviously
520                 passing arguments to the constructor is not possible with pre-instantiated
521                 objects.
522             </para>
523         </example>
525         <example id="zend.xmlrpc.server.use.attach-several-classes-namespaces">
526             <title>Attaching several classes using namespaces</title>
528             <para>
529                 The example below illustrates attaching several classes, each
530                 with their own namespace.
531             </para>
533             <programlisting language="php"><![CDATA[
534 require_once 'Services/Comb.php';
535 require_once 'Services/Brush.php';
536 require_once 'Services/Pick.php';
538 $server = new Zend_XmlRpc_Server();
539 $server->setClass('Services_Comb', 'comb');   // methods called as comb.*
540 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
541 $server->setClass('Services_Pick', 'pick');   // methods called as pick.*
542 echo $server->handle();
543 ]]></programlisting>
544         </example>
546         <example id="zend.xmlrpc.server.use.exceptions-faults">
547             <title>Specifying exceptions to use as valid fault responses</title>
549             <para>
550                 The example below allows any <classname>Services_Exception</classname>-derived
551                 class to report its code and message in the fault response.
552             </para>
554             <programlisting language="php"><![CDATA[
555 require_once 'Services/Exception.php';
556 require_once 'Services/Comb.php';
557 require_once 'Services/Brush.php';
558 require_once 'Services/Pick.php';
560 // Allow Services_Exceptions to report as fault responses
561 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
563 $server = new Zend_XmlRpc_Server();
564 $server->setClass('Services_Comb', 'comb');   // methods called as comb.*
565 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
566 $server->setClass('Services_Pick', 'pick');   // methods called as pick.*
567 echo $server->handle();
568 ]]></programlisting>
569         </example>
571         <example id="zend.xmlrpc.server.use.custom-request-object">
572             <title>Utilizing custom request and response objects</title>
574             <para>
575                 Some use cases require to utilize a custom request object.
576                 For example, <acronym>XML/RPC</acronym> is not bound to
577                 <acronym>HTTP</acronym> as a transfer protocol. It is possible to use
578                 other transfer protocols like <acronym>SSH</acronym> or telnet to send
579                 the request and response data over the wire. Another use case is
580                 authentication and authorization. In case of a different transfer
581                 protocol, one need to change the implementation to read request data.
582             </para>
584             <para>
585                 The example below instantiates a custom request object and
586                 passes it to the server to handle.
587             </para>
589             <programlisting language="php"><![CDATA[
590 require_once 'Services/Request.php';
591 require_once 'Services/Exception.php';
592 require_once 'Services/Comb.php';
593 require_once 'Services/Brush.php';
594 require_once 'Services/Pick.php';
596 // Allow Services_Exceptions to report as fault responses
597 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
599 $server = new Zend_XmlRpc_Server();
600 $server->setClass('Services_Comb', 'comb');   // methods called as comb.*
601 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
602 $server->setClass('Services_Pick', 'pick');   // methods called as pick.*
604 // Create a request object
605 $request = new Services_Request();
607 echo $server->handle($request);
608 ]]></programlisting>
609         </example>
611         <example id="zend.xmlrpc.server.use.custom-response-object">
612             <title>Specifying a custom response class</title>
614             <para>
615                 The example below illustrates specifying a custom response class
616                 for the returned response.
617             </para>
619             <programlisting language="php"><![CDATA[
620 require_once 'Services/Request.php';
621 require_once 'Services/Response.php';
622 require_once 'Services/Exception.php';
623 require_once 'Services/Comb.php';
624 require_once 'Services/Brush.php';
625 require_once 'Services/Pick.php';
627 // Allow Services_Exceptions to report as fault responses
628 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
630 $server = new Zend_XmlRpc_Server();
631 $server->setClass('Services_Comb', 'comb');   // methods called as comb.*
632 $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
633 $server->setClass('Services_Pick', 'pick');   // methods called as pick.*
635 // Create a request object
636 $request = new Services_Request();
638 // Utilize a custom response
639 $server->setResponseClass('Services_Response');
641 echo $server->handle($request);
642 ]]></programlisting>
643         </example>
644     </sect2>
646     <sect2 id="zend.xmlrpc.server.performance">
647         <title>Performance optimization</title>
649         <example id="zend.xmlrpc.server.performance.caching">
650             <title>Cache server definitions between requests</title>
652             <para>
653                 The example below illustrates caching server definitions between requests.
654             </para>
656             <programlisting language="php"><![CDATA[
657 // Specify a cache file
658 $cacheFile = dirname(__FILE__) . '/xmlrpc.cache';
660 // Allow Services_Exceptions to report as fault responses
661 Zend_XmlRpc_Server_Fault::attachFaultException('Services_Exception');
663 $server = new Zend_XmlRpc_Server();
665 // Attempt to retrieve server definition from cache
666 if (!Zend_XmlRpc_Server_Cache::get($cacheFile, $server)) {
667     $server->setClass('Services_Comb', 'comb');   // methods called as comb.*
668     $server->setClass('Services_Brush', 'brush'); // methods called as brush.*
669     $server->setClass('Services_Pick', 'pick');   // methods called as pick.*
671     // Save cache
672     Zend_XmlRpc_Server_Cache::save($cacheFile, $server);
675 // Create a request object
676 $request = new Services_Request();
678 // Utilize a custom response
679 $server->setResponseClass('Services_Response');
681 echo $server->handle($request);
682 ]]></programlisting>
683         </example>
685         <note>
686             <para>
687                 The server cache file should be located outside the document root.
688             </para>
689         </note>
691         <example id="zend.xmlrpc.server.performance.xmlgen">
692             <title>Optimizing XML generation</title>
694             <para>
695                 <classname>Zend_XmlRpc_Server</classname> uses
696                 <classname>DOMDocument</classname> of <acronym>PHP</acronym>
697                 extension <code>ext/dom</code> to generate it's
698                 <acronym>XML</acronym> output. While <code>ext/dom</code> is
699                 available on a lot of hosts it is not exactly the fastest.
700                 Benchmarks have shown, that <classname>XMLWriter</classname>
701                 from <code>ext/xmlwriter</code> performs better.
702             </para>
704             <para>
705                 If <code>ext/xmlwriter</code> is available on your host, you can
706                 select a the <classname>XMLWriter</classname>-based generator
707                 to leaverage the performance differences.
708             </para>
710             <programlisting language="php"><![CDATA[
711 require_once 'Zend/XmlRpc/Server.php';
712 require_once 'Zend/XmlRpc/Generator/XMLWriter.php';
714 Zend_XmlRpc_Value::setGenerator(new Zend_XmlRpc_Generator_XMLWriter());
716 $server = new Zend_XmlRpc_Server();
718 ]]></programlisting>
719         </example>
721         <note>
722             <title>Benchmark your application</title>
724             <para>
725                 Performance is determined by a lot of parameters and
726                 benchmarks only apply for the specific test case. Differences
727                 come from <acronym>PHP</acronym> version, installed extensions, webserver and
728                 operating system just to name a few. Please make sure to
729                 benchmark your application on your own and decide which
730                 generator to use based on <emphasis>your</emphasis> numbers.
731             </para>
732         </note>
734         <note>
735             <title>Benchmark your client</title>
737             <para>
738                 This optimization makes sense for the client side too. Just
739                 select the alternate <acronym>XML</acronym> generator before
740                 doing any work with <classname>Zend_XmlRpc_Client</classname>.
741             </para>
742         </note>
743     </sect2>
744 </sect1>
745 <!--
746 vim:se ts=4 sw=4 et: