3. Automatic conversion of php functions into xmlrpc methods (and vice versa)

For the extremely lazy coder, two functions have been added that allow to convert a php function into an xmlrpc method, and a remotely exposed xmlrpc method into a local php function. Note that this comes with many caveats.

3.1. wrap_xmlrpc_method

$new_php_function_name = wrap_xmlrpc_method(,  
 ,  
 ,  
 ,  
 ,  
 ); 
 ;
 ;
 ;
 ;
 ;
 ;

Given an xmlrpc server and a method name, creates a php wrapper function that will call the remote method and return results using native php types for both params and results. The generated php function will return an xmlrpcresp object for failed xmlrpc calls.

The server must support the system.methodSignature xmlrpc method call for this function to work.

The $client param must be a valid xmlrpc_client object, previously created with the address of the target xmlrpc server, and to which the preferred communication options have been set.

The $signum param is optional. Its purpose is to indicate which method signature to use, if the given server method has multiple signatures (defaults to 0).

The $timeout and $protocol params are the same as in the xmlrpc_client::send() method.

If set, the optional $funcname indicates which name should be used for the generated function. In case it is left null, the function name will be auto-generated.

In case of an error during generation of the wrapper function, FALSE is returned, otherwise the name of the new function.

Known limitations: server must support system.methodsignature for the wanted xmlrpc method; for methods that expose multiple signatures, only one can be picked; for remote calls with nested xmlrpc params, the caller of the generated php function has to encode on its own the params passed to the php function if these are structs or arrays whose (sub)members include values of type base64.

Note: calling the generated php function 'might' be slow: a new xmlrpc client is created on every invocation and an xmlrpc-connection opened+closed. An extra 'debug' param is appended to the parameter list of the generated php function, useful for debugging purposes.

Example usage:

$c = new xmlrpc_client('http://phpxmlrpc.sourceforge.net/server.php');

$function = wrap_xmlrpc_method($client, 'examples.getStateName');

if (!$function)
  die('Cannot introspect remote method');
else {
  $stateno = 15;
  $statename = $function($a);
  if (is_a($statename, 'xmlrpcresp')) // call failed
  {
    echo 'Call failed: '.$statename->faultCode().'. Calling again with debug on';
    $function($a, true);
  }
  else
    echo "OK, state nr. $stateno is $statename";
}

3.2. wrap_php_function

$dispatch_map_definition = wrap_php_function($funcname,  
 $wrapper_function_name); 
 $funcname;
 $wrapper_function_name;

Given a user-defined PHP function, create a PHP 'wrapper' function that can be exposed as xmlrpc method from an xmlrpc_server object and called from remote clients.

The optional $wrapper_function_name specifies the name that will be used for the auto-generated function.

Since php is a typeless language, to infer types of input and output parameters, it relies on parsing the javadoc-style comment block associated with the given function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64) in the docblock @param tag is also allowed, if you need the php function to receive/send data in that particular format (note that base64 encoding/decoding is transparently carried out by the lib, while datetime vals are passed around as strings).

Known limitations: requires PHP 5.0.3 +; only works for user-defined functions, not for PHP internal functions (reflection does not support retrieving number/type of params for those); the wrapped php function will not be able to programmatically return an xmlrpc error response; functions returning php objects will generate "special" xmlrpc responses: when the xmlrpc decoding of those responses is carried out by this same lib, using the appropriate param in php_xmlrpc_decode, the objects will be rebuilt.

In short: php objects can be serialized, too (except for their resource members), using this function. Other libs might choke on the very same xml that will be generated in this case (i.e. it has a nonstandard attribute on struct element tags)

Example usage:

/**
* State name from state number decoder. NB: do NOT remove this comment block.
* @param integer $stateno the state number
* @return string the name of the state (or error description)
*/
function findstate($stateno)
{
  global $stateNames;
  if (isset($stateNames[$stateno-1]))
  {
    return $stateNames[$stateno-1];
  }
  else
  {
    return "I don't have a state for the index '" . $stateno . "'";
  }
}

// wrap php function, build xmlrpc server
$methods = array();
$findstate_sig = wrap_php_function('findstate');
if ($findstate_sig)
  $methods['examples.getStateName'] = $findstate_sig;
$srv = new xmlrpc_server($methods);