devxlogo

Cross the Gap Between PHP and Java

Cross the Gap Between PHP and Java

hese days, using sophisticated application frameworks to build your network server applications is understandable, but sometimes such frameworks are overkill. When you strip networking down to its bare essentials, network sockets offer lot of flexibility and simplicity. With a little communications programming between PHP and Java, you can establish an extensible layer that handles the annoying details of creating a custom network protocol.

As you’ll see, PHP is not only excellent for quick-and-dirty scripting. More and more developers also are using it to build sophisticated Web applications. Java, of course, has been used to build Web applications for years, but as anyone who has used a Java-based Web framework knows, it isn’t the easiest technology to use.

This article shows how to connect a PHP-based application to a custom Java server. The demonstration doesn’t use Enterprise Java Beans (EJB) or any particular Java-based server framework. Instead, it creates a simple custom TCP/IP Java server to demonstrate how easy it is. Then, you’ll see how to access such a server from Java.

Architecture
PHP programming is sometimes mistakenly referred to as client-side scripting. Technically, PHP runs on the server side, but because it is usually used to generate HTML?which the user sees directly?it is sometimes thought of as the client-side portion of server-side code.

In fact, the system in this article uses PHP in this very sense (click here to download the source code). It consists of a Java portion, which performs server-side computation, and a PHP portion, which generates HTML. Both portions run on the server and communicate using a TCP/IP socket. The terms client and server can be a little ambiguous in this context, so the article refers instead to the PHP portion and the Java portion.

The Java Portion
Using the following code, the example Java server takes two numbers, adds them, and sends the sum back to the user:

public Map transform( Map map ) {  // Get the two addends from the input packet.  int i0 = ((Integer)map.get( "addend0" )).intValue();  int i1 = ((Integer)map.get( "addend1" )).intValue();  // Add them, producing a sum.  int sum = i0+i1;  // Build an ouptut packet.  Map answer = new HashMap();  answer.put( "sum", new Integer( sum ) );  return answer;}

This code lives in a class called AdditionServer (see Listing 2), which inherits from a base class called Server (see Listing 1). Server takes care of the details involved with reading the input packet from the TCP/IP stream and writing the answer to the output TCP/IP stream.

With these details addressed, creating a new service and running it inside a Java server is very easy. All you have to do is inherit from Server and implement a method called transform(), which takes an input packet and turns it into an output packet.

The PHP Portion
In order for the PHP code to connect to the Java server, it must speak TCP/IP. Luckily, PHP has full support for TCP/IP. The following PHP code sends two numbers to the addition server (see Listing 7), which adds them and sends them back:

// Make a connection to the Java server.$mc = new MapConnection( "localhost", 5000 );// Build a packet containing the two numbers.$problem = array( "addend0"=>100, "addend1"=>44 );// Send the packet to the server.$mc->write( $problem );// Get the sum from the server.$answer = $mc->read();$sum = $answer["sum"];

Again, the communication details are hidden?in this case, in the PHP class MapConnection, which is implemented in a file called MapConnection, in the file mapstream.PHP (see Listing 6).

Data Structures
To send the data back and forth, you put the two numbers to be added into a packet (in this case, just a PHP associative array) on the PHP side. Since PHP arrays are flexible and contain everything you need, you can easily put anything you need into the data packet. (The implementation for this article lets you put strings, integers, and floating-point values in the array. You can also put arrays inside arrays to any level of nesting.) The code in MapConnection converts the packet into a byte-stream, and then sends it across the wire to the server.

Meanwhile, on the Java side, this same data must be turned into a Java data structure. Java does not have dynamic arrays the way PHP does, but it does have the next best thing: the java.util.Map interfaces. Building and taking apart such structures is not as easy as it is in PHP, but it’s semantically equivalent.

This data conversion is one of the fine points of communicating between PHP and Java. The previous code has defined a data structure?a dynamic associative array containing strings, integers, and floating point values?that can exist comfortably in both languages. It’s then just a simple matter of writing code in both Java and PHP to convert these data structures to and from byte streams.

Abstracting Away the Details
The PHP and Java portions of this system aren’t very complicated. Aside from the details of bundling and unbundling the data, and the addition itself, it contains very little code. This is as it should be: the application is simple, so the code is simple as well. The communication details, which are the same for all possible services, are kept out of sight. This is an excellent example of abstracting away the details.

You may think creating a custom server and a custom protocol to go with it is overkill for an application this simple. In fact, since PHP supports addition, this example really is overkill. But it makes perfect sense in other cases. For example, you might have a custom database implemented in Java, or you may want to interface with a Java-based chat system rather than trying to rewrite it in PHP. In either case, you’d just determine what you need to send back and forth, and use MapConnection and Server to take care of the communication for you.

Delving into the Details
The details are safely hidden from the user-level code, but how do they actually work?

On the Java side, you’ll find five classes. The Server (see Listing 1) class deals with the networking. It listens on a socket and accepts connections. Each time a connection comes in, it creates an object called a Handler, which runs in its own thread. The Handler reads a request from the socket, calls transform() to process it, and sends the result back with the following code:

while (true) {  Map map = min.readMap();  map = transform( map );  mout.write( map );}

The default implementation of transform() just returns the packet unchanged. Of course, you can override this, as you did with AdditionServer (see Listing 2).

In the preceding code snippet, min and mout are instances of the classes MapInputStream (see Listing 3) and MapOutputStream (see Listing 4). These classes read and write Map objects and are subclasses of FilterInputStream and FilterOutputStream, respectively. Specifically, they handle Map objects, which contain strings, integers, doubles, and other Maps. In turn, these classes use DataInputStream and DataOutputStream, respectively, to encode integers, strings, and doubles. They both inherit an interface called MapStream (see Listing 5), which contains just a few constants that encode different kinds of values in the byte stream.

The process on the PHP side is rather similar. In fact, the code for readObject() and writeObject() are fairly similar among the PHP code in mapstream.PHP (see Listing 6) and the Java code in MapInputStream.java and MapOutputStream.java. PHP doesn’t have DataInputStream or DataOutputStream, so you have to write those yourself and make sure they encode the data in the same way. This functionality is encoded in readRawInt(), writeRawInt(), readRawDouble(), writeRawDouble(), and so on. The similarities between the PHP and Java code are the results?and benefit?of using a data structure that is at home in both languages.

A Mechanism for Ad-hoc Remote Procedure Calls
If the communication between PHP and Java teach you anything, it is the importance of using an abstraction layer to hide messy and unimportant details. In this case, you were able to turn the simple function of adding two numbers into a full-fledged, multi-threaded network service, while keeping the actual addition code very simple and clean. The communication details were hidden away in specialized classes, which can be re-used for any other network service.

What you’ve actually built is an ad-hoc remote procedure call (RPC) mechanism. RPC systems can be pretty complicated, but you avoided that by both making your system simple and robust, and allowing for very general data structures.

The downside is your network protocol is a bit wasteful on bytes, but that is probably not a concern for simple applications. And if it does become a problem, you can always change the protocol layer?without having to disrupt the application code. The code in this article can also serve as an excellent tool for rapid prototyping.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist