This post is part of a series exploring Thrift using PHP, with the eventual goal of incorporating Twitter's FlockDB into a PHP Web front end. Today, I present the simplest use of Thrift possible, aptly named, "Hello World." It depends on your first having installed Thrift. I have tested the following code using Thrift 0.2.0 on a Snow Leopard iMac, and made it available for download from Github.
Thrift file
thrift/helloworld.thrift
- service HelloWorld {
- oneway void hello(1:string juicy)
- }
One service, one method taking a string as its single argument. The
oneway
modifier means the client will not wait for a response after sending the hello
request. A natural consequence of this is the return type must be void
for oneway
methods. Generate php source from the thrift file:thrift --gen php:server thrift/helloworld.thrift
Two freshly minted php files should have been deposited in
gen-php/helloworld
: HelloWorld.php
and helloworld_types.php
. We haven't defined any types, so can ignore helloworld_types.php
. The scaffolding of our new service is all in HelloWorld.php
. Looking through the source, some things to notice:- include_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
- include_once $GLOBALS['THRIFT_ROOT'].'/packages/helloworld/helloworld_types.php';
This version of Thrift maintains a liberal reliance on the global THRIFT_ROOT. When we make the actual client and server for HelloWorld, we will have to set the THRIFT_ROOT global. For convenience, I put the whole thrift-0.2.0 directory in /usr/local/thrift-0.2.0, so my THRIFT_ROOT will be
/usr/local/thrift-0.2.0/lib/php/src
.Notice the location of helloworld_types.php. The files I just generated have to be placed in the packages directory:
- mkdir /usr/local/thrift-0.2.0/lib/php/src/packages
- cp -r gen-php/helloworld/ /usr/local/thrift-0.2.0/lib/php/src/packages/helloworld/
The remainder of
HelloWorld.php
contains type definitions for our HelloWorld service. The interface HelloWorldIf
is used by both the client and the server when communicating to the other. The client code, HelloWorldClient
, has been completely generated! There is also a processor the server uses to deal with requests as they come in from a client, HelloWorldProcessor
. NOTE: If you did not use the 'server' sub-option when generating the php files, the processor will not have been generated. People construct servers using php so infrequently, this is probably a good corner to cut. However, in our example the processor is required if only to avoid getting tri-lingual.PHP Client
php/stream-client.php
- <?php
- $GLOBALS['THRIFT_ROOT'] = '/usr/local/thrift-0.2.0/lib/php/src';
- require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/transport/TPhpStream.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/packages/helloworld/HelloWorld.php';
- $stdout = new TPhpStream(TPhpStream::MODE_W);
- $protocol = new TBinaryProtocol($stdout);
- $client = new HelloWorldClient($protocol);
- $stdout->open();
- $send = implode(' ', array_slice($_SERVER['argv'], 1));
- $client->hello($send);
Adjust your THRIFT_ROOT for where you have deposited the Thrift download. Usually you would make a client send information through a socket, and that is very possible. But that requires we have a server listening on that socket, and you have to get a little clever to do that in php. So I propose side stepping the issue and creating a client that communicates with STDOUT (
$stdout
). The binary protocol comes standard with Thrift, use it ($protocol
. And we create the HelloWorldClient
around the selected stream/protocol pair ($client). Before using the client, the stream (or socket) must be opened. And the string sent to the server will be all the command line arguments. Try it out:> php php/stream-client.php 'Hello Thrift!!!' ?hello Hello Thrift!!! >
That's pretty ugly, but at least we can see that the raw binary protocol is working.
PHP Server
php/stream-server.php
- <?php
- $GLOBALS['THRIFT_ROOT'] = '/usr/local/thrift-0.2.0/lib/php/src';
- require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/transport/TPhpStream.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
- require_once $GLOBALS['THRIFT_ROOT'].'/packages/helloworld/HelloWorld.php';
- class HelloWorldHandler implements HelloWorldIf {
- public function hello($juicy) {
- $time = time();
- echo "$time\t$juicy\n";
- }
- }
- $handler = new HelloWorldHandler();
- $processor = new HelloWorldProcessor($handler);
- $transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W));
- $protocol = new TBinaryProtocol($transport, true, true);
- $transport->open();
- $processor->process($protocol, $protocol);
- $transport->close();
Adjust the THRIFT_ROOT as needed. On the server side we have to actually implement the HelloWorld service.
HelloWorldHandler::hello
takes the string given, writing it and a timestamp to STDOUT. The rest of this simple example creates a server reading from STDIN and writing to STDOUT. To test it, we can pipe the output from the stream-client to the stream-server:> php php/stream-client.php 'Hello World!!!' | php php/stream-server.php 1282863497 Hello World!!!
Better! It has begun. We can create a dirt simple client and server using php and the standard streams. Next you might like to try out the slightly more advanced tutorials included with the Thrift download (thrift-0.2.0/tutorial).
Next post: analysis of Flockdb.thrift