在 WebSphere sMash 中集成 Java 和 PHP

开始之前

首先花数分钟细读一下 Project Zero 网站,以对其进行熟悉。您可以加入 Project Zero 社区、参与项目工作或加入论坛,您可以在论坛中对项目的每个开发阶段进行评论。本文假定您已经在计算机上安装了合适的 Java Development Kit (JDK)。您还需要熟悉 PHP 的概念。

建议阅读 Project Zero、WebSphere sMash 和 PHP 入门。其中介绍了如何下载 WebSphere sMash 和创建 PHP 应用程序。这篇文章假定您已经有了能与 PHP 一起工作的 WebSphere sMash。请注意,该文章中只有到“运行应用程序”部分的步骤是有必要进行的工作。

编者注: IBM® WebSphere sMash 和 IBM WebSphere sMash Developer Edition 基于得到高度认可的 Project Zero 孵化器项目。Project Zero 是 WebSphere sMash 的开发社区,并将继续为开发人员提供开发应用程序的免费平台,为开发人员提供最新版本、最新功能和社区支持。

 

引言

本文说明如何使用 Java Bridge 从 PHP 访问 Java 类。其中将讨论如何调用 Java 方法和访问字段(实例和静态字段)。另外还将讨论异常处理及 PHP 和 Java 之间的类型转换。

 

ZSL、WebSphere sMash 和 Apache Lucene

有关真实示例,本文逐步说明了使用 PHP 编写的简单搜索引擎的创建工作,此引擎可使用 Apache Lucene 建立文件索引和进行搜索。Apache Lucene 是一个高性能的全功能文本搜索引擎库,完全使用 Java 编写。这是一项适合很多需要全文本搜索的应用程序使用的技术。

ZSL 在其编写的 WebSphere sMash 应用程序中使用 Apache Lucene。ZSL® 希望改进其开发人员之间的信息共享情况。为了解决此问题,他们建立了 Mashup 来对源代码和文档库(PDF、PowerPoint、Word、Excel 和很多其他格式)进行索引。此应用程序提供了从整个企业方便快捷访问代码片段的能力。

 

在 WebSphere sMash 中创建应用程序

第一步是在 Eclipse 中创建新项目:

  1. 选择 File -> New -> Project...,并在对话框中展开 Zero 目录。
  2. 选择 WebSphere sMash PHP Application,并单击 Next,如图 1 中所示。
  3. 给项目命名(例如 MyJavaProject)并单击 Finish。您的项目现在已创建。

    图 1. “创建新的 WebSphere sMash 项目”对话框

创建并调用 Java 对象

接下来,编写创建和调用 Java 对象的 PHP 脚本:

  1. 右键单击 public 文件夹并选择 New -> File
  2. 给文件命名(例如 Java.php)并单击 Finish
  3. 在文件中添加以下代码:
    <?php
        $file = new Java("java.io.File", __FILE__, FALSE);
        var_dump($file);
        var_dump($file->isDirectory());
    ?>
    
  4. 在 Eclipse 中右键单击项目名,并选择 Run As -> WebSphere sMash Application,以运行示例代码。
  5. 会在 localhost 的端口 8080 启动 Web 服务器。
  6. 现在可以打开浏览器,指向 http://localhost:8080/Java.php,您将看到以下输出,如图 2 中所示。

    图 2. 调用 Java 对象的 Web 浏览器输出

 

此示例代码显示了使用内置 Java 类的 PHP 脚本。此 Java 类创建 Java 类的实例,并调用最佳匹配构造函数(从脚本传递任何参数)。在此示例中,根目录为 "/"FALSE。脚本将其存储在名为 $file 的 PHP 变量中。脚本然后像处理普通 PHP 对象一样对该对象调用方法,在此示例中我们将其命名为 isDirectory 方法。

此功能非常强大,允许 PHP 脚本访问任何 Java 类。请注意,该 Java 类必须位于应用程序类路径上,java.io.File 是核心 Java 类库的一部分,因此始终可用。

 

使用 Java 集合类

Java 提供了丰富的集合类,包括映射、集、列表和队列。此示例代码显示了 PHP 脚本可以如何利用这些类。正如前面所述,创建一个新 PHP 脚本(例如,MoreJava.php)并添加以下代码:

图 3. 使用 Java 集合类的 Web 浏览器输出

现在可以打开浏览器,指向 http://localhost:8080/MoreJava.php,您将看到以下输出,如图 3 中所示。

 

 

PHP 脚本:

  • 创建 Java HashMap 类的实例。
  • 将包含 Java Bridge! 的字符串存储在映射中。
  • 突出 Java 和 PHP 类型之间的互操作性。
  • 创建 PHP 数组,并将其存储在 Java 映射中,如下面的代码所示。
    $array = array(1, 2, 3, 4, 5);
    $map->put("stuff", $array);
    

对映射进行 put 调用时,PHP 数组会转换为最接近的 Java 类型,即 Java Map。与此类似,当 get 调用从 $map 读回值时,会将其转换回常规 PHP 数组。这可以在不进行任何复制的情况下进行,因为 PHP 数组具有两个个性类型,即 PHP 数组和 Java 映射。

 

遍历 Java 集合

尝试使用以下代码替换 MoreJava.php 脚本:

现在可以打开浏览器,指向 http://localhost:8080/MoreJava.php,您将看到以下输出,如图 4 中所示。


图 4. 遍历 Java 集合的 Web 浏览器输出

 

此示例显示了使用 Java ArrayList 类的 PHP。而且,还从 ArrayList 获得了迭代器,并从头到尾对集合进行了扫描。迭代器的内容按顺序写入,首先是字符串 Java Bridge!,然后是 Java Date 对象,最后是包含五个数字的 PHP 数组。

 

访问静态方法和字段

静态方法和字段使用 JavaClass 进行访问。对 Java 有一点差异,其中静态方法和字段直接使用类名称进行直接访问。以下代码说明了如何对 java.lang.System 调用 currentTimeMillis

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

图 5 显示了在浏览器中运行此脚本的输出。


图 5. 访问静态方法的 Web 浏览器输出

 

访问静态字段与此类似。下面的代码显示 java.lang.Integer 类中的 MIN_VALUE 静态字段:

<?php
	$integerClass = new JavaClass("java.lang.Integer");
	var_dump($integerClass->MIN_VALUE);
?>

图 6 显示了在浏览器中运行此脚本的输出。

 

图 6. 访问静态字段的 Web 浏览器输出

 

在 PHP 中捕获 Java 异常

Java Bridge 将 Java 异常转换为 JavaException 的实例。这是在 PHP 脚本中捕获的通用 PHP 异常。以下代码片段显示了对 java.lang.System 上的 getProperty 的无效调用:

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

图 7 显示了在浏览器中运行此脚本的输出。


图 7. 捕获 Java 异常的 Web 浏览器输出

请注意,在 WebSphere sMash 1.0 中,getCause 方法将返回基础 Java 异常的类名称,而不是 所导致的异常本身。在最新的 Project Zero 构建版本中,这个奇怪的行为已经得到修复,将返回实际的 Java 异常。

 

从 Java 到 PHP 的类型转换

表 1 显示了 Java 类型如何转换为 PHP 类型。常规的做法是转换为尽可能减少潜在损失的类型(例如,将 int 转换为 byte)。另请注意,转换同样适用于受限和不受限 Java 类型,例如 Integerint


表 1. 从 Java 到 PHP 的类型转换

Java 类型 PHP 类型 注释
null null  
Integer/int int  
Double/double double  
Boolean/boolean bool  
Byte/byte int  
Character/char int  
Short/short int  
Long/long int  
Float/float double  
byte[] string  
String string 此 PHP 字符串使用运行时编码进行编码。
Map array 各个元素的类型按照此表进行转换,包括嵌套映射。
Object[] array 请参见数组转换
Anything Else! n/a 这使用 Java Bridge 包装,成为通用 PHP 对象。

Project Zero 网站提供了关于转换的更多信息。

 

 

Java Bridge 局限性

Java Bridge 旨在作为让 PHP 脚本使用 Java 类的简单方法使用。考虑这一点,有几个其中未包含的更为高级的功能。其中最重要的是可靠地调用重载方法。

Java Bridge 完全 根据提供的参数数量选择方法或构造函数。如果存在多个可能性,则 Java Bridge 将选择第一个方法或构造函数并试用。这极为简单,使用错误的参数类型调用构造函数或方法时,会引发异常。

使用签名选择重载

选择合适的重载的问题已经在最新的 Project Zero 构建版本(在 WebSphere sMash 1.0 中 可用)中通过添加新的 JavaSignature 类得到了解决。JavaSignature 允许脚本通过定义参数类型查找以下内容来明确指定调用哪个构造函数或方法:

 

JavaSignature 的参数来自以下 PHP 常量:

  • JAVA_BOOLEAN
  • JAVA_BYTE
  • JAVA_CHAR
  • JAVA_SHORT
  • JAVA_INT
  • JAVA_LONG
  • JAVA_FLOAT
  • JAVA_DOUBLE
  • JAVA_STRING
  • JAVA_OBJECT

 

在前面的示例中,示例选择了 java.lang.String 上的构造函数,此构造函数接受单个 Java String 作为其参数 (JAVA_STRING)。多个参数使用逗号分隔,例如,newJavaSignature(JAVA_STRING, JAVA_INT)。可以使用 JAVA_ARRAY 修饰符指定 Java 类型的数组。例如,以下代码将选择字符串数组: newJavaSignature(JAVA_STRING | JAVA_ARRAY).

以下代码片段显示了一个 JavaSignature,它选择 java.lang.String 上的 valueOf 方法的重载。请注意签名作为第一个参数如何传递到方法调用。Java Bridge 知道对其进行检查来获取签名。

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

方法名称区分大小写

PHP 中的方法不区分大小写,而 Java 区分大小写。Java Bridge 区分大小写,因此 PHP 方法名称必须与 Java 方法名称完全匹配。

静态方法和字段

Java 开发人员习惯使用类名称调用静态方法和字段(例如,Integer.MAX_VALUE)。这在 PHP 中尚不可能,因此必须使用 JavaClass。脚本创建 JavaClass 的实例,并使用此实例调用静态方法和访问静态字段。这种做法并不常见,因为需要开发人员创建仅用于访问非实例(静态)方法和字段的对象的实例。

遍历集合

前面的示例代码说明了如何遍历 Java 集合。这相当冗长,比 PHP foreach 语句的开销少。目前,Java Bridge 并未将 Java 迭代器和 PHP foreach 语句集成。以下代码说明了如何在 PHP 中使用 Java 迭代器:
$iterator = $list->iterator();
while ($iterator->hasNext() == TRUE) { 
	 var_dump($iterator->next()); echo "<br/>";
}

将所有这些应用到实际示例中

下一部分将前面部分所讨论的内容集中到 Java Bridge 的真实使用示例中。此示例创建了使用 PHP 编写的简单搜索引擎,可以使用 Apache Lucene 建立文件索引和进行搜索。Apache Lucene 是一个高性能的全功能文本搜索引擎库,完全使用 Java 编写。它适合于需要全文本搜索(特别是跨平台)的几乎任何应用程序。有关更多信息,请参见 Apache Lucene 站点。

创建索引

第一步是获得 Lucene。我们要使用最新版本的 Lucene(尽管其工作并不完美),因为我们希望与 Lucene 的 PHP 实现(基于 Lucene 2.2.0)进行比较。

  1. 下载 lucene-2.2.0.tar.gz 。例如,从以下镜像位置下载: http://mirror.cc.columbia.edu/pub/software/apache/lucene/java/archive/.
  2. 解压缩文件(或运行 tar -xvzf lucene-2.2.0.tar.gz)。
  3. 找到两个 JAR 文件,lucene-core-2.2.0.jarlucene-demos-2.2.0.jar

 

下一步编写创建 Lucene 搜索引擎的 PHP 脚本:

  1. 在 Java 透视图中,通过选择 File -> New -> Other 来创建新应用程序。选择 WebSphere Smash PHP Application 并将其命名为 Lucene
  2. 右键单击 public 文件夹并选择 New -> File
  3. 将文件命名为 index.php 并单击 Finish
  4. 将前面的两个 Lucene JAR 文件复制到 Lucene/lib 目录中。
  5. 要确保 WebSphere sMash 使用 Lucene Java 库,请右键单击项目名称 Lucene 并选择 WebSphere sMash Tools -> Resolve
  6. 在文件中添加以下代码:
    <html>
    <head>
       <title>Search Index</title>
    </head>
    <body>
    	<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!">
       	</form>   
    </body>
    </html>
    
  7. 右键单击项目名称 Lucene 并选择 WebSphere sMash Application -> Run,以运行应用程序。将 Web 浏览器指向本地服务器,如 http://localhost:8080/index.php。其外观与图 8 中所示类似。

    图 8. “选择目录和文件扩展名”页
  1. 不要尝试建立任何内容的索引,因为还需要添加其他代码。最后,提交表单时,PHP 脚本将创建 Lucene 搜索索引,并使用目录中具有匹配扩展名的所有文件对其进行填充。也会向下递归到开始目录,并在此过程中添加相应的文件。
  2. 接下来,将以下 PHP 代码添加到 index.php 中:
  1. 尚不要运行,因为还没有完成!代码从全局上下文获取表单变量,并检查是否已经填充。如果已经跳出,则会调用 index_directory 函数。此函数将在后面进行说明,负责将任何匹配的文件添加到 Lucene 搜索引擎。
  2. 接下来,将以下 PHP 代码添加到 index.php 中:

本文将不会介绍 Java Lucene API 的详细信息。简单来说,此代码用于创建 IndexWriter 对象。这是键索引对象,当脚本在目录中进行递归时,文件添加到其中。请注意,可以根据很多不同的源(例如,RAM 磁盘)进行反向索引。在此示例中,从常规文件系统读取文件,因此将使用 FSDirectory 类。

一旦设置 IndexWriter,脚本将调用 recursive_index_directory 来实际进行索引工作。此函数传递 IndexWriter,即起始目录以及候选文件要匹配的文件扩展名。

以下部分的代码是索引脚本的最后一部分。其中的大部分代码都是通用 PHP 脚本,枚举了目录中的所有文件,并按顺序逐一处理。确定了要索引的文件后,将会创建 FileDocument。需要使用文件的完全限定路径建立此对象,然后将其添加到 IndexWriter

 

将 Web 浏览器指向脚本,并填写表单变量,如图 9 中所示。

图 9. 建立目录索引时的 Web 浏览器输出

 

单击 Index!,脚本将对所选文件进行索引。在上面的示例中,脚本指向一段 C 源代码,对五个源文件进行了索引。如果刷新 Eclipse 项目,会发现一个名为 Index 的新目录。此目录包含 Lucene 搜索引擎产生的搜索索引文件,如图 10 中所示。

图 10. WebSphere sMash 应用程序的目录结构

 

将搜索查询添加到应用程序

最后一步是写入一个允许用户针对索引运行搜索的表单。

  1. 右键单击 public 文件夹并选择 New -> File
  2. 将文件命名为 search.php 并单击 Finish
  3. 在文件中添加以下代码:

 

运行此脚本,Web 浏览器中的情况将与图 11 所示类似。

图 11. 搜索查询页

 

 

接下来,将以下 PHP 代码添加到 search.php 中:

 

  1. 和前面一样,此脚本使用了多个 Lucene 类。此脚本的要点在于,没有使用 index.php 之类的 IndexWriter 类,而使用了 IndexSearcher。其配置的目录与前面创建索引文件的目录相同。用户在该表单中输入的字符串将随后用于创建查询对象。Lucene QueryParser 提供了解析查询字符串的简单方法。

    有了经过解析的查询后,脚本就准备好在 IndexSearcher 上运行搜索了。这将返回脚本所枚举的命中列表,显示每个项目的路径。
  2. 将 Web 浏览器指向 search.php 并输入一些搜索术语,如图 12 中所示。

    图 12. 运行搜索查询的 Web 浏览器输出

 

在此示例中,找到匹配关键字“TSRM”和“int”的五个匹配项。Lucene 提供了强大的查询语法,能够支持各种搜索术语。关于可能的搜索查询的更多信息,请访问 Apache Lucene 站点。

性能比较

如果仔细分析一下我们添加到 index.php 的源代码,则您会看到对 microtime 的一些调用和一些注释,其中表明我们希望检查性能。

 

 

 

 

结束语

在本文中,您进行了以下工作:

  • 使用 PHP 和 WebSphere sMash 创建应用程序。
  • 使用 Java Bridge 创建和调用 Java 对象。
  • 探索从 PHP 脚本使用 Java 集合的方法。
  • 了解 Java Bridge 如何进行类型强制转换和异常处理。
  • 开发基于 Java Lucene 库的搜索引擎。
  • 了解 Java Lucene 库的性能。

 

 

我们执行的检查是简单计时检查。我们非常有兴趣比较一下使用三个不同的软件创建索引的时间:

  • 通过 WebSphere sMash Java Bridge 调用的 Lucene 的 Java 实现。
  • 从 Java 应用程序调用的 Java Lucene。
  • Zend Framework 中的 Lucene 的 PHP 实现。

 

为了进行公平的比较,我们使用了 Lucene Version 2.2.0,即 Zend 实现所基于的版本。我们还使用了 Lucene SimpleAnalyser。有关 Zend 实现的详细讨论超出了本文的范围。不过,它是 Lucene 代码的可靠端口,会生成与 Java 版本生成的格式完全相同的格式。

性能比较所执行的是对 PHP 5.3 源树下的所有 PHP 测试脚本(*.phpt 文件)进行索引。创建和优化索引所花费的时间如表 2 中所示。


表 2. Lucene 搜索的性能比较

技术 时间(秒)
WebSpere sMash Java Bridge 9
Java Lucene 8
Zend Search Lucene 200

这可以让我们简要了解使用这些现成技术的时间比较情况。所有这些计时都打开了 Java JIT,这在 Lucene 之类的应用程序中的执行时间方面会产生巨大的差异。

这些原因都不能作为不使用 Zend 实现的原因。事实上,如果不使用 Java,而您主要的开发语言是 PHP,则使用同样是 PHP 编写的搜索引擎会带来很多优势。方便地理解和修改代码之类的考虑事项可能会比唯一的性能优势更为重要。

更有意思的是使用 PHP 及 Java Bridge 与使用 Java 应用程序间的比较。二者时间接近的事实表明,我们不会在 Java Bridge 中或在 Java VM 上运行 PHP 浪费太多时间。

当然,还有其他通过 PHP 使用 Java Bridge 的实现。例如,Zend Platform 中有一个商业实现,而 sourceforge.net 提供了一个开源实现。虽然我们没有使用这些实现,但它们的存在为将 Java 用于最适用的场合(算法性能)并同时充分利用 PHP 的易用性提供了支持。

如果您重复进行这些实验,可能会发现创建索引的过程中存在着细微的差别。Zend 实现的较为有用的功能之一是,能够创建与 Java 实现格式完全相同的索引,而这就意味着可以使用标准 Java 工具对其进行检查(例如,可以从 Luke 站点下载的 Luke)。这些差异都相对比较容易解释,不会影响耗时比较的结果。例如,PHP 和 Java 分析工具之间就存在细微差别。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值