Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="toc" />

<ac:macro ac:name="note"><ac:parameter ac:name="title">Work in Progress</ac:parameter><ac:rich-text-body>
<p>This page is work in progress. Please discuss and feel free to edit, rephrase, extend with more cases and examples.</p></ac:rich-text-body></ac:macro>

<h2>Overview</h2>

<p>RPC stands for Remote Procedure Call. The purpose of the Zend\Rpc component is to allow the Zend Framework 2 users to make (distributed) RPC calls in an easy way while reusing their existing classes. This component goes even further by allowing the developers to choose how to serialize and transport the information depending on the current environment and their needs. </p>

<h2>References</h2>

<p>TDB</p>

<h2>Dependencies on PHP modules</h2>

<ul>
<li>php_zmq <a class="external-link" href="http://php.zero.mq/">http://php.zero.mq/</a></li>
<li>php_msgpack <a class="external-link" href="http://msgpack.org/">http://msgpack.org/</a></li>
</ul>

<h2>Dependencies on Other Framework Components</h2>

<h2>Class Index</h2>

<ul>
<li>Zend\Rpc\Server</li>
<li>Zend\Rpc\Client</li>
<li>Zend\Rpc\Hub\Zmq</li>
<li>Zend\Rpc\Transport</li>
<li>Zend\Rpc\Transport\Adapter</li>
<li>Zend\Rpc\Transport\Zmq</li>
<li>Zend\Rpc\Transport\Rabbitmq</li>
<li>Zend\Rpc\Serializer</li>
<li>Zend\Rpc\Serializer\Adapter</li>
<li>Zend\Rpc\Serializer\Json</li>
<li>Zend\Rpc\Serializer\Msgpack</li>
</ul>

<h2>Theory of Operation</h2>

<p>TBD</p>

<h3>Client</h3>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Rpc;
use Zend\Rpc\Serializer as Serializer;

/**

  • RPC Client

request message:
{"c":"<function-name>", "a":(arguments-list), "kw": {key-value-dict}}

response message:

Unknown macro: { "ok"}

*/
class Client {
/**

  • @var Zend\Rpc\Transport\Adapter
    */
    protected $transport;

/**

  • @var string
    */
    protected $serializerType;

/**

  • Initializes the client
  • @param Zend\Rpc\Transport\Adapter $transport
  • @param string $serializerType
    */
    public function __construct($transport, $serializerType = Serializer::JSON)
    Unknown macro: { $this->transport= $transport; $this->serializerType = $serializerType; }

/**

  • Handles all client calls.
    *
  • @param string $name
  • @param array $arguments
  • @return mixed
    */
    public function __call($name, $arguments) {
  1. @todo: try to introspect the PHP code and see if return value is expected
    $wantResponse = true;

$request = array (
"c" => $name,
"a" => $arguments
);

  1. todo: make the timeout more flexible
    $timeout = 30;

$serializerInstance = Serializer::factory($this->serializerType);
$response = $this->transport->send(
sprintf("%02.d%s", $this->serializerType, $serializerInstance->encode($request)),
$wantResponse,
$timeout);
$response = $serializerInstance->decode($response);
if ($response['ok'])

Unknown macro: { return $response['res']; }

else

Unknown macro: { throw new Exception($response['ex']); }

}
}
]]></ac:plain-text-body></ac:macro>

<h3>Server</h3>

<p>Zend\Rpc\Server.php</p>
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Rpc;

/**

  • RPC Server

request message:
{"c":"<function-name>", "a":(arguments-list), "kw": {key-value-dict}}

response message:

Unknown macro: { "ok"}

*/
class Server {
protected $functionList = array();
protected $classInstance = null;
protected $transport = null;

/**

  • Initializes the server
  • @param Zend\Rpc\Transport\Adapter $transport
    */
    public function __construct($transport)
    Unknown macro: { $this->transport = $transport; }

/**

  • Adds a function alias to the server
  • @param string $name the name of the function
  • @param callback $callback
    */
    public function addFunction($name, $callback)
    Unknown macro: { $this->functionList[$name] = $callback; }

/**

  • Adds a class to the server
    *
  • @param object $classInstance
    */
    public function addClass($classInstance)
    Unknown macro: { $this->classInstance = $classInstance; }

/**

  • Handles single incoming message at a time
  • @param mixed $message
  • @return mixed

*/
public function handleMessage($message) {
$serializerType = intval(substr($message, 0, 2));
$serializerInstance = Serializer::factory($serializerType);

try

Unknown macro: { $message = $serializerInstance->decode(substr($message,2)); }

catch(\Exception $ex)

Unknown macro: { $response = array( "ok" => 0, "res"=> "", "ex" => $ex->getMessage()."n". $ex->getTraceAsString() ); return $serializerInstance->encode($response); }

$name = $message['c'];
$args = $message['a'];
$result = null;
try {
if (isset($this->functionList[$name]))

Unknown macro: { $result = call_user_func_array($this->functionList[$name],$args); }

else if($this->classInstance) {
if (!method_exists($this->classInstance, $name))

Unknown macro: { throw new Exception('Invalid method '.get_class($this->classInstance).'->'.$name.'!'); }

$result = call_user_func_array(array($this->classInstance, $name),$args);
}
}
catch(\Exception $ex)

Unknown macro: { $response = array ( "ok" => 0, "res" => "", "ex" => $ex->getMessage()."n". $ex->getTraceAsString() ); return $serializerInstance->encode($response); }

$response = array(
"ok" => 1,
"res" => $result,
"ex" => ""
);

return $serializerInstance->encode($response);
}

/**

  • Starts handling the incoming requests
    */
    public function handle()
    Unknown macro: { $this->transport->setOnReceive(array($this, 'handleMessage')); $this->transport->listen(); }

    }
    ]]></ac:plain-text-body></ac:macro>

<h3>Transport</h3>
<p>Zend\Rpc\Transport\Adapter.php</p>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
namespace Zend\Rpc\Transport;

interface Adapter {
/**

  • Sets the callback that is called when a data is received in the listening socket
    */
    public function setOnReceive($callback);

/**

  • Connects to a listeining port
    */
    public function connect();

/**

  • Starts listening and accepting connections
    */
    public function listen();

/**

  • Sends message via the transport
  • @param string $message
  • @param boolean $wantResponse - specifies if the call will block until a response is given back
  • @param int $timeout
  • @return mixed
  • @throws \Exception
    */
    public function send($message, $wantResponse=false, $timeout=null);

/**

  • Disconnects the transport
    */
    public function disconnect();
    }

]]></ac:plain-text-body></ac:macro>

<h3>Serializer</h3>
<p>Zend\Rpc\Serializer\Adapter.php</p>
<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
<?php
namespace Zend\Rpc\Serializer;

interface Adapter {
/**

  • Encode the given PHP variable as string
  • @param mixed $data
  • @return string
    */
    public function encode($data);

/**

  • Decode the given data into valid PHP variable
  • @param string $data
  • @return mixed
    */
    public function decode($data);
    }
    ]]></ac:plain-text-body></ac:macro>

<h2>Use cases</h2>

<h3>Create a RPC server</h3>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[

use Zend\Rpc\Server as Server;
use Zend\Rpc\Transport\Zmq as Transport;

class Calculator {
public function plus($a, $b)

Unknown macro: { return $a+$b; }

}

$transport = new Transport("tcp://*:6000");

$server = new Server($transport);
$server->addClass(new Calculator());
$server->handle();

]]></ac:plain-text-body></ac:macro>

<h3>Create a PRC client</h3>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
use Zend\Rpc\Client as Client;
use Zend\Rpc\Transport\Zmq as Transport;

$transport = new Transport("tcp://*:6000");

$client = new Client($transport);
print $client->plus(5, 3)."\n";
]]></ac:plain-text-body></ac:macro>

<h3>Distributed Computing</h3>

<p>In the case of RabbitMQ as a transport the RPC is already distributed. In the case of ZeroMQ we can create a hub using the following code<br />
TBD</p>

Labels:
rpc rpc Delete
zeromq zeromq Delete
rabbitmq rabbitmq Delete
distributed distributed Delete
computing computing Delete
cloud cloud Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.