Integrating Java and PHP in WebSphere sMash

The WebSphere® sMash environment enables rapid development of interactive Web applications based on popular Web technologies such as PHP, and it lets you reuse existing Java™ assets from PHP scripts. This article introduces the Java Bridge and shows how to access Java classes from PHP.


Ant Phillips, Software Developer, IBM

Photo: Ant PhillipsAnt Phillips is a Software Developer in IBM's Java Technology Centre in Hursley, United Kingdom. His current focus is on WebSphere sMash, a simple environment for creating dynamic Web applications. Before joining IBM, Ant was the technical lead at an innovative startup based in Newbury, UK. In previous lives, Ant worked for Sony® and Microsoft® and thoroughly enjoyed visiting Tokyo, Seattle, and several places in between. In his spare time, he plays as much sport as his wife and two children let him get away with.

Zoe Slattery, Software Engineer, IBM

Photo: Zoe SlatteryZoe Slattery is a Technology Evangelist working for IBM Hursley, United Kingdom. Her current interests are in in Enterprise OSGi, in particular the development of open source OSGi components in Apache Aries. Zoe is also a member of the Apache Software Foundation.

24 September 2008

Also available in Chinese Russian Japanese

Before you get started

Take a few minutes to peruse and get familiar with the Project Zero Web site. You can join the Project Zero community, contribute to the project, or join the discussion forum, where you can comment on the project through each stage of its development. This article assumes that you have a suitable Java Development Kit (JDK) installed on your machine. You also need to be familiar with the concepts of PHP.

Get started with Project Zero, WebSphere sMash, and PHP is recommended reading. It shows how to download WebSphere sMash and create a PHP application. This article assumes you have a working version of WebSphere sMash with PHP. Note it is only necessary to work through the steps in that article up to the "Running the application" section.

Editor's note: IBM® WebSphere sMash and IBM WebSphere sMash Developer Edition are based on the highly acclaimed Project Zero incubator project. Project Zero is the development community for WebSphere sMash and will continue to offer developers a cost-free platform for developing applications with the latest builds, the latest features, and the support of the community.


The article shows how to access Java classes from PHP using the Java Bridge. It discusses calling Java methods and accessing fields, both instance and static. It also covers exception handling and type conversion between the PHP and Java worlds.

ZSL, WebSphere sMash, and Apache Lucene

For a real world example, this article steps through the creation of a simple search engine written in PHP that can index and search files using Apache Lucene. Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java. It is a technology suitable for many applications that require full-text search.

ZSL used Apache Lucene in a WebSphere sMash application they wrote. ZSL® wanted to improve information sharing between their developers. To solve this problem, they put together a mashup to index their source code and documentation library (PDF, PowerPoint, Word, Excel, and many others). The application provides quick and easy access to code snippets from across the company.

Creating an application in WebSphere sMash

The first step to get started is to create a new project in Eclipse:

  1. Select File -> New -> Project... and expand the Zero category in the dialog.
  2. Select WebSphere sMash PHP Application and click Next as shown in Figure 1.
  3. Give your project a name (for example, MyJavaProject) and click Finish. Your project is now created.
    Figure 1. Create a new WebSphere sMash project dialog
    Create a new WebSphere sMash project dialog

Creating and calling Java objects

Next, write a PHP script that creates and calls a Java object:

  1. Right-click on the public folder and select New -> File.
  2. Give your file a name (for example, Java.php) and click Finish.
  3. Add the following code into the file:
        $file = new Java("", __FILE__, FALSE);
  4. Run the sample code by right-clicking on the project name in Eclipse and select Run As -> WebSphere sMash Application.
  5. A Web server is started on port 8080 of your localhost.
  6. You can now go to a browser and direct it to http://localhost:8080/Java.php, and you see the following output as shown in Figure 2.
    Figure 2. Web browser output from calling Java objects
    Web browser output from calling Java objects

This sample code shows a PHP script using the built in Java class. The Java class creates an instance of a Java class and calls the best matching constructor, passing any arguments from the script. In this example, the root directory is "/" and FALSE. The script stores it in a PHP variable called $file. The script then calls methods on the object just as if it was a normal PHP object, so in this example we call it the isDirectory method.

This capability is powerful and gives PHP scripts access to any Java class. Note that the Java class must be on the application class path is part of the core Java class library and so it is always available.

Using the Java collection classes

Java has a rich set of collection classes, including maps, sets, lists, and queues. This sample code shows how a PHP script can leverage those classes. As before, create a new PHP script (for example, MoreJava.php) and add the following code:

    $map = new Java("java.util.HashMap");
    $map->put("title", "Java Bridge!");
    $array = array(1, 2, 3, 4, 5);
    $map->put("stuff", $array);
    echo $map->get("title");

You can now go to a browser and direct it to http://localhost:8080/MoreJava.php, and you see the following output as shown in Figure 3.

Figure 3. Web browser output from using the Java collection classes
Web browser output from using the Java collection classes

The PHP script:

  • Creates an instance of a Java HashMap class.
  • Stores a string containing Java Bridge! in the map.
  • Highlights interoperability between Java and PHP types.
  • Creates a PHP array and stores it in the Java map as shown in the code below.
    $array = array(1, 2, 3, 4, 5);
    $map->put("stuff", $array);

When the put call is invoked on the map, the PHP array is converted to its closest equivalent Java type, which is a Java Map. Likewise, when the get call reads the value back from $map, it is converted back to a regular PHP array. This is possible without any copying because PHP arrays have two personalities, PHP arrays and Java maps.

Iterating over Java collections

Try replacing the MoreJava.php script with the following code:

	$list = new Java("java.util.ArrayList");
	$date = new Java("java.util.Date", 70, 9, 4);
	echo "<br/>";
	$list->add("Java Bridge!");
	$list->add(array(1, 2, 3, 4, 5));
	$iterator = $list->iterator();
	while ($iterator->hasNext() == TRUE) { 
	     var_dump($iterator->next()); echo "<br/>";

You can now go to a browser and direct it to http://localhost:8080/MoreJava.php, and you see the following output as shown in Figure 4.

Figure 4. Web browser output from iterating over Java collections
Web browser output from iterating over Java collections

This example shows PHP using a Java ArrayList class. Furthermore, it also gets an iterator from the ArrayList and scans through the collection from start to finish. The contents of the iterator are written in order, starting with the string Java Bridge!, then the Java Date object, and finishing with the PHP array containing five numbers.

Accessing static methods and fields

Static methods and fields are accessed using JavaClass. This is a little different to Java, where static methods and fields are accessed directly using the class name. The following code shows how to call currentTimeMillis on java.lang.System:

	$system = new JavaClass("java.lang.System");
	echo("</br>Current time: ".

Figure 5 shows the ouput from running this script in a browser.

Figure 5. Web browser output from accessing static methods
Web browser output from accessing static methods

Accessing static fields is similar. The following code displays the MIN_VALUE static field in the java.lang.Integer class:

	$integerClass = new JavaClass("java.lang.Integer");

Figure 6 shows the ouput from running this script in a browser.

Figure 6. Web browser output from accessing static fields
Web browser output from accessing static fields

Catching Java exceptions in PHP

The Java Bridge converts Java exceptions into instances of JavaException. This is a generic PHP exception class that is caught in PHP scripts. The following code snippet shows an invalid call to getProperty on java.lang.System:

	try { 
		$system = new JavaClass("java.lang.System");
	} catch (JavaException $exception) { 
	    echo "Cause: ".$exception->getCause();

Figure 7 shows the ouput from running this script in a browser.

Figure 7. Web browser output from catching Java exceptions
Web browser output from catching Java exceptions

Note that in WebSphere sMash 1.0, the getCause method returns the class name of the underlying Java exception, not the causing exception itself. In the latest Project Zero builds, this oddity has been fixed to return the actual Java exception.

Type conversion from Java to PHP

Table 1 shows how Java types are converted to PHP types. The general approach is to convert to a type that minimizes any potential loss (for example, when converting an int to a byte). Note also that the conversions apply equally for boxed and unboxed Java types, such as Integer and int.

Table 1. Type conversion from Java to PHP
Java type PHP type Comments
Byte/byte int 
Stringstring The PHP string is encoded using the runtime encoding.
Maparray The types of individual elements are converted as per this table, including nested maps.
Object[]array See the array conversion.
Anything Else! n/a This is the wrapped by a Java Bridge and becomes a generic PHP object.

More information about type conversion is available at the Project Zero Web site.

Java Bridge limitations

The Java Bridge is intended to be a simple way for PHP scripts to use Java classes. With that in mind, there are several more advanced features that it does not contain. The most significant of these is calling overloaded methods reliably.

The Java Bridge selects a method or constructor based solely on the number of arguments supplied. If more than one possibility exists, then the Java Bridge selects the first one and tries that. This is extremely simplistic and leads to an exception being thrown when a constructor or method is called with the wrong argument types.

Selecting overloads with signatures

The problem with selecting a suitable overload has been solved in the latest Project Zero builds (this is not available in WebSphere sMash 1.0) with the addition of a new JavaSignature class. The JavaSignature allows a script to specify exactly which constructor or method is invoked by defining the argument types to look for the following:

	$signature = new JavaSignature(JAVA_STRING);
	$string = new Java("java.lang.String", 
          $signature, "Hello World!");

	var_dump($string->split(" "));

The arguments for JavaSignature are drawn from the following PHP constants:


In the previous example, the example selects a constructor on java.lang.String that takes a single Java String as its argument (JAVA_STRING). Multiple arguments are comma separated, for example, newJavaSignature(JAVA_STRING, JAVA_INT). You can specify arrays of Java types using the JAVA_ARRAY modifier. For example, the following selects an array of strings: newJavaSignature(JAVA_STRING | JAVA_ARRAY).

The following snippet shows a JavaSignature selecting an overload of the valueOf method on java.lang.String. Note how the signature is passed as the first argument to the method call. The Java Bridge knows to check there for signatures.

	$class = new JavaClass("java.lang.String");
	$signature = new JavaSignature(JAVA_INT);
	var_dump($class->valueOf($signature, 1234567890));

Case-sensitive method names

Methods in PHP are not case-sensitive, while Java is case-sensitive. The Java Bridge is case-sensitive and so the PHP method name must match the Java method name exactly.

Static methods and fields

Java developers are used to invoking static methods and fields using the class name (for example, Integer.MAX_VALUE). This is not yet possible in PHP and so you must use the JavaClass. A script creates an instance of JavaClass and uses that to call static methods and to access static fields. This is unusual because it requires a developer to create an instance of an object just to access non-instance (static) methods and fields!

Iterating over collections

The sample code earlier showed how to iterate over a Java collection. This is fairly long-winded and less expressive than a PHP foreach statement. At the moment, the Java Bridge does not integrate Java iterators and PHP foreach statements. The following code shows how to use Java iterators in PHP:

$iterator = $list->iterator();
while ($iterator->hasNext() == TRUE) { 
	 var_dump($iterator->next()); echo "<br/>";

Putting it all together in a real world example

The next section pulls together the previous sections to describe a real world use of the Java Bridge. The example creates a simple search engine written in PHP that can index and search files using Apache Lucene. Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java. It is suitable for nearly any application that requires full-text search, especially cross-platform. For more information, see the Apache Lucene site.

Creating an index

The first step is to get Lucene. We are not going to use the most recent version of Lucene (although it will work perfectly well) because we want to make comparisons with the PHP implementation of Lucene, which is based on Lucene 2.2.0.

  1. Download lucene-2.2.0.tar.gz. For example, from the following mirror:
  2. Unzip the file (or run tar -xvzf lucene-2.2.0.tar.gz).
  3. Find the two JAR files, lucene-core-2.2.0.jar and lucene-demos-2.2.0.jar.

The next step is to write a PHP script that creates a Lucene search index:

  1. In the Java perspective, create a new application by selecting File -> New -> Other. Select WebSphere Smash PHP Application and call it Lucene.
  2. Right-click on the public folder and select New -> File.
  3. Give your file the name of index.php and click Finish.
  4. Copy the two Lucene JAR files from earlier into the Lucene/lib directory.
  5. To make sure that WebSphere sMash uses the Lucene Java libraries, right-click on the project name, Lucene, and select WebSphere sMash Tools -> Resolve.
  6. Add the following code into the file:
       <title>Search Index</title>
    	<form name="input" action="/index.php" method="POST">
    		<label for="directory">Directory:</label>
       	    <input type="text" name="directory">
    		<label for="extension">File Extension:</label>
        	<input type="text" name="extension">
          	<input type="submit" name="action" value="Index!">
  7. Run the application by right-clicking on the project name Lucene and selecting WebSphere sMash Application -> Run. Point the Web browser at the local server, such as http://localhost:8080/index.php. It looks similar to Figure 8.
    Figure 8. Selecting a directory and file extension page
    Selecting a directory and file extension page
  8. Do not try and index anything yet because there is more code to add. Eventually when the form is submitted, the PHP script will create a Lucene search index and populate it with all the files in the directory that have a matching extension. It will also recurse down from the starting directory, adding files as it goes.
  9. Now add the following PHP code into index.php:
    $directory = dirname(__FILE__)."/../index";
    if (file_exists($directory) === FALSE) {
    define("INDEX_DIRECTORY", $directory);
    try {	
    	$extension = zget('/request/params/extension');
    	if (strlen($extension) > 0) {
    		$directory = zget('/request/params/directory');
    		if (strlen($directory) > 0) {
    			index_directory($directory, $extension);
    } catch (JavaException $exception) {
    	echo "Index creation failed [".
  10. Do not run it yet because it is not finished! The code gets the form variables from the Global Context and checks whether they have been filled out. If they have been filled out, it calls the index_directory function. This function is explained next and is responsible for adding any matching files into the Lucene search index.
  11. Now add the following PHP code into index.php:
     * This creates an index from scratch and adds all the documents
     * by recursing from the directory passed in. It also checks
     * each candidate file to see if it matches the file extension.
    function index_directory($path, $extension) {
        	echo "Indexing! [".$path.",".$extension."]</br>";
    	// Uses the SimpleAnalyzer because we will do a performance comparison 
              with the PHP 
    	// implementation of Lucene in the Zend Framework and it is the closest match	
    	$analyser = new Java("org.apache.lucene.analysis.SimpleAnalyzer");
    	$policy = new Java("org.apache.lucene.index.KeepOnlyLastCommitDeletionPolicy");
    	$file = new Java("", INDEX_DIRECTORY, FALSE);
    	$file_directory = new JavaClass("");
    	$directory = $file_directory->getDirectory($file);
    	$writer = new Java("org.apache.lucene.index.IndexWriter", 
    		$directory, TRUE, $analyser, TRUE, $policy);
    	// Insert some calls to microtime() for comparison
    	$start_time = get_microtime();	
    	recursive_index_directory($writer, $path, $extension);
    	$count = $writer->docCount();
    	// Lucene only matches the first 10,000 tokens by default
    	$end_index_time = get_microtime();
    	$end_time = get_microtime();
    	echo "Finished indexing [".$count." documents]</br>";
    	$t1 = $end_index_time - $start_time;
    	$t2 = $end_time - $end_index_time;
    	echo "Time to index  = $t1 </br>";
    	echo "Time to optimize  = $t2 </br>";

    Explaining the details of the Java Lucene API is beyond the scope of this article. In a nutshell, the code is creating an IndexWriter object. This is the key indexing object to which files will be added as the script recurses through directories. Note that you can back indexing by many different sources, for example, a RAM disk. In this example, the files are being read from a regular file system and so it uses the FSDirectory class.

    Once the IndexWriter is set up, the script calls recursive_index_directory to actually do the indexing. This function is passed the IndexWriter, which is the directory to start from and the file extension to match candidate files against.

    The following section of code completes the indexing script. Most of this code is general purpose PHP script that enumerates all the files in a directory and processes each in turn. Once it determines a file to be indexed, it creates a FileDocument. This is set up with the fully-qualified path to the file, and then adds it to the IndexWriter.
     * Processes a file by adding it to the indexer.
    function index_file($writer, $path) {
    	echo "Indexing file [".$path."]</br>";
    	try {		
    		// A few of the files we indexed in the examples have non
    		// UTF-8 characters so we just skip indexing those files!
    		$file = new Java("", $path, FALSE);
    		$file_document = new JavaClass("org.apache.lucene.demo.FileDocument");
    		$document = $file_document->Document($file);
    	} catch (JavaException $exception) {
    		echo "Invalid characters in file!\n";
    function get_microtime(){
    	list($part_one,$part_two) = explode(' ',microtime());
    	return ((float) $part_one + (float) $part_two);
     * Indexes all matching files (by extension) in the directory tree. 
    function recursive_index_directory($writer, $path, $extension) {
        echo "Indexing directory [".$path."]</br>";
        // Remove any trailing slash first
        if (substr($path, -1) == '/') {
            $path = substr($path, 0, -1);
        // Make sure the directory is valid
        if (is_dir($path) == TRUE) {
    	    if (is_readable($path) == TRUE) {
    		 $handle = opendir($path);
    		  // Scan through the directory contents
        		  $extension_length = strlen($extension);
    		  while (FALSE !== ($item = readdir($handle))) {
    		    if ($item != '.') {
    		        if ($item != '..') {
    		        $index_path = ($path.'/'.$item);
    		        if (is_dir($index_path) == TRUE) {
    			        $writer, $index_path, $extension);
    		   } else {
    		         $position = strpos(strtolower($index_path), $extension);
    		         // Very rough and ready way to check for trailing extension!
    		         if ($position == (strlen($index_path)-$extension_length)) {
    			  index_file($writer, $index_path, $extension);
        return TRUE;
  12. Point the Web browser at the script and fill out the form variables as shown in Figure 9.
    Figure 9. Web browser output from indexing a directory
    Web browser output from indexing a directory
  13. Click Index! and the script indexes the files selected. In the example above, the script pointed to some C source code and it indexed five source files. If you refresh your Eclipse project, you have a new directory called Index. This directory contains the search index files produced by the Lucene search engine as shown in Figure 10.
    Figure 10. Directory structure of a WebSphere sMash application
    Directory structure of a WebSphere sMash application

The final step is to write a form that allows a user to run searches against the index:

  1. Right-click on the public folder and select New -> File.
  2. Give your file the name of search.php and click Finish.
  3. Add the following code into the file:
    	<form name="input" action="/search.php" method="POST">
    		<label for="query">Search Query:</label>
       	    <input type="text" name="query">
          	<input type="submit" name="action" value="Search!">
  4. Run this script and the Web browser looks like Figure 11.
    Figure 11. Search query page
    Search query page
  5. Now add the following PHP code into search.php:
     * This runs a search through an index already created.
    function search_index($path, $query) {
    	echo "Searching for [".$query."]</br>";
    	$file = new Java("", $path, FALSE);
    	$file_directory = new JavaClass("");
    	$directory = $file_directory->getDirectory($file);
    	$searcher = new Java("", $directory);	
    	$analyser = new Java("org.apache.lucene.analysis.SimpleAnalyzer");
    	$parser = new Java("org.apache.lucene.queryParser.QueryParser", 
    		"contents", $analyser);
    	$parsed_query = $parser->parse($query);	
    	$hits = $searcher->search($parsed_query);	
    	$count = $hits->length();
    	for ($index = 0; $index < $count; $index++) {
    		$document = $hits->doc($index);
    		echo $index.") ".$document->get("path")."</br>";
    	echo "</br>Finished searching [".$count." hits]</br>";
    try {	
    	$directory = dirname(__FILE__)."/../index";
    	define("INDEX_DIRECTORY", $directory);
    	$query = zget('/request/params/query');
    	if (strlen($query) > 0) {
    		search_index($directory, $query);
    } catch (JavaException $exception) {
    	echo "Index search failed [".$exception->getMessage()."]</br>";	

    As before, this script makes use of several Lucene classes. The essence of the script is that, instead of using the IndexWriter class like index.php, it uses an IndexSearcher. This is configured with the same directory where the index files were created earlier. The string that was entered by the user in that form is then used to create a query object. The Lucene QueryParser provides an easy way to parse query strings.

    With the query parsed, the script is ready to run the search on the IndexSearcher. This returns a list of hits, which the script enumerates, displaying the path for each item.
  6. Point a Web browser at the search.php and enter some search terms as shown in Figure 12.
    Figure 12. Web browser output from running a search query
    Web browser output from running a search query

In this example, five hits were found matching the keywords "TSRM" and "int". Lucene has a powerful query syntax that can support a wide variety of search terms. More information about the possible search queries is available from the Apache Lucene site.

Performance comparisons

If you were looking carefully at the source code that we added to index.php, you may have noticed some calls to microtime and a few comments, which indicated that we would want to check the performance.

The checks that we performed are simple timing checks. We were interested in comparing the time it takes to create an index using three different pieces of software:

  • The Java implementation of Lucene called via the WebSphere sMash Java Bridge.
  • Java Lucene called from a Java application.
  • The PHP implementation of Lucene in the Zend Framework.

To make this a fair comparison, we used Lucene Version 2.2.0, which is what the Zend implementation is based on. We also used the Lucene SimpleAnalyser. A detailed discussion of the Zend implementation is beyond the scope of this article. However, it is a faithful port of the Lucene code and it generates indexes that have identical format to those generated by the Java version.

The performance comparison was to index all of the PHP test scripts (*.phpt files) under the PHP 5.3 source tree. The times taken to create and optimize the index are shown in Table 2.

Table 2. Performance comparison for Lucene search
Technology Time in seconds
WebSpere sMash Java Bridge 9
Java Lucene 8
Zend Search Lucene 200

This is gives a quick idea of how timings compare using these technologies "out-of-the- box". The Java JIT is switched on in these timings, and in an application like Lucene, it makes a considerable difference in execution times.

Neither of these reasons is taken as a reason not to use the Zend implementation. In fact, if you are not using Java and your principle development language is PHP, using a search engine that is also written in PHP has many advantages. Considerations such as understanding and modifying the code easily may outweigh those of raw performance.

What is more interesting is the comparison between using PHP and the Java Bridge and using a Java application. The fact that the timings are close tells us that we are not wasting too much time in the Java Bridge, or in fact, in running PHP on the Java VM.

There are, of course, other PHP to Java Bridges. For example, there is a commercial implementation in the Zend Platform and an open source implementation available from While we have not used either of these implementations, the fact that they exist lend support to the argument for using Java for what it is good for (algorithmic performance) and taking advantage of the fact that PHP is easy to use.

If you repeat these experiments, you may notice slight differences in the indexes that are created. One of the useful features of the Zend implementation is that it creates indexes of exactly the same format as the Java implementation, which means that you can check them with standard Java tools (for example, Luke, which you can download from the Luke site). These differences are all relatively easy to explain and do not affect the timing comparison. For example, there are slight differences between the PHP and Java analyzers.


In this article, you:

  • Created an application in PHP and WebSphere sMash.
  • Used the Java Bridge to create and invoke Java objects.
  • Explored using Java collections from PHP scripts.
  • Learned how the Java Bridge does type coercion and exception handling.
  • Developed a search engine based on the Java Lucene libraries.
  • Looked at the performance of the Java Lucene libraries.

Now that you have completed this article, you can expand your use of Java libraries and PHP scripting. Why not combine some more Java libraries with PHP in WebSphere sMash? Let us how you know how you are doing in the Project Zero forums. If you want to learn more about the Zero Global Context and other relevant topics, see the WebSphere sMash Developer's Guide listed in the Resources section below.


The authors would like to thank Naveen Noel Jakkamsetti at ZSL Inc. for his help with this article.



Get products and technologies

  • You can find full instructions for downloading and installing WebSphere sMash for PHP at the Project Zero site.



developerWorks: Sign in

Required fields are indicated with an asterisk (*).

Need an IBM ID?
Forgot your IBM ID?

Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.


All information submitted is secure.

Dig deeper into WebSphere on developerWorks

Zone=WebSphere, Java technology
ArticleTitle=Integrating Java and PHP in WebSphere sMash