Среда WebSphere® sMash позволяет быстро разрабатывать интерактивные Web-приложения на основе популярных Web-технологий, таких как PHP, и позволяет повторно использовать существующие ресурсы Java™, обращаясь к ним из скриптов PHP. Эта статья знакомит вас с Java Bridge и объясняет, как получить доступ к классам Java из PHP.

Ант Филлипс, программист, IBM

Photo: Ant PhillipsАнт Филлипс— программист центра технологий IBM Java Technology Centre в Херсли, Великобритания. В настоящее время основным направлением его работы является WebSphere sMash — простая среда для создания динамических Web-приложений. До прихода в IBM Ант был техническим руководителем инновационной фирмы в Ньюбери, Великобритания. До этого Ант успел поработать в Sony® и Microsoft® и проводил свое время в Токио, Сиэтле и в поездках между ними. Свободное время он посвящает занятиям спортом, насколько ему это позволяют жена и двое детей.



Зоя Слэттери, программист, IBM

Photo: Zoe SlatteryЗоя Слэттери— программист компании IBM в Херсли, Великобритания. В настоящее время интересуется разработкой открытого ПО и PHP-приложений. В прошлом Зоя работала во многих сферах, связанных с информационными технологиями. Начинала программировать на FORTRAN, работала над параллельными системами для численных расчетов и управляла архивом данных в Европейском центре среднесрочных прогнозов погоды. Позднее она руководила командами разработчиков, работавшими над Java Virtual Machine компании IBM и открытыми реализациями библиотек классов Java.



02.07.2012

Прежде чем начать

Не пожалейте нескольких минут и посетите Web-сайт Project Zero. Вы можете присоединиться к сообществу Project Zero, принять участие в проекте или в дискуссионном форуме, где сможете комментировать все этапы проекта. Эта статья предполагает, что на вашем компьютере установлена подходящая версия Java Development Kit (JDK). Также вы должны быть знакомы с концепциями PHP.

Рекомендуется также ознакомиться со статьей Приступаем к работе с Project Zero, WebSphere sMash и PHP. В ней объясняется, как загрузить WebSphere sMash и создать приложение на PHP. В рамках этой статьи предполагается, что у вас есть рабочая версия WebSphere sMash с PHP. Заметьте, что вам нужно изучить эту статью только до раздела "Запуск приложения".

Примечание редактора: IBM® WebSphere sMash и IBM WebSphere sMash Developer Edition основаны на получившем широкую известность проекте инкубатора Project Zero. Project Zero — это сообщество разработчиков WebSphere sMash, которое развивает бесплатную платформу разработки приложений, предлагая новые версии, дополнительные функции и экспертную поддержку.


Введение

В этой статье рассказывается, как получить доступ к классам Java из PHP с помощью Java Bridge, рассматриваются вызов методов Java и доступ к полям (как к полям экземпляра, так и к статическим полям). Кроме того, в статье описывается обработка исключений и преобразование типов между PHP и Java.


Компания ZSL, WebSphere sMash и Apache Lucene

В качестве наглядного примера в статье приведены этапы создания простой поисковой системы, написанной на PHP, которая индексирует и ищет файлы с помощью библиотеки Apache Lucene. Apache Lucene представляет собой высокопроизводительную полнофункциональную библиотеку для полнотекстового поиска, написанную полностью на Java. Она подходит для многих приложений, которым необходим полнотекстовый поиск.

Компания ZSL использовала Apache Lucene в своем приложении WebSphere sMash с целью улучшения процесса обмена информацией для своих разработчиков. Для решения этой проблемы компания ZSL® создала гибридное приложение для индексирования исходного кода и библиотеки документации (в PDF, PowerPoint, Word, Excel и др.). Это приложение обеспечивает быстрый и простой доступ к фрагментам кода в пределах всей компании.


Создание приложения в WebSphere sMash

Первое, с чего нужно начать, - это создание нового проекта в Eclipse:

  1. Выберите File -> New -> Project... (Файл -> Создать -> Проект...) и откройте в появившемся диалоговом окне категорию Zero.
  2. Выберите WebSphere sMash PHP Application (приложение WebSphere sMash PHP) и щелкните на Next (Далее), как показано на рисунке 1.
  3. Дайте имя своему проекту (например, MyJavaProject) и щелкните Finish (Готово). Проект создан.
    Рисунок 1. Диалоговое окно для создания нового проекта WebSphere sMash
    Диалоговое окно для создания нового проекта WebSphere sMash

Создание и вызов объектов Java

Теперь напишите скрипт на PHP, который создает и вызывает объект Java:

  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 (Запустить как -> Приложение WebSphere sMash).
  5. На порте 8080 вашей локальной станции запустится Web-сервер.
  6. Теперь вы можете открыть браузер и перейти на страницу http://localhost:8080/Java.php. Здесь вы увидите что-то похожее на рисунок 2.
    Рисунок 2. Результат вызова объектов Java в Web-браузере
    Результат вызова объектов Java в Web-браузере

В этом примере кода показан скрипт PHP, использующий встроенный класс Java. Этот класс Java создает экземпляр класса Java и вызывает наиболее подходящий конструктор, передавая ему аргументы из скрипта. В данном примере корневая директория называется "/" и FALSE. Скрипт сохраняет ее в переменной PHP с именем $file. Затем скрипт вызывает методы для этого объекта точно так же, как если бы он был обычным объектом PHP, поэтому в данном примере мы вызываем метод isDirectory.Эта возможность очень эффективна и предоставляет скриптам PHP доступ к любому классу Java. Заметьте, что класс Java должен находиться в пути класса приложения java.io.File, который является частью корневой библиотеки классов Java и поэтому всегда доступен.


Использование классов-коллекций Java

Java имеет богатый набор классов-коллекций, таких как карты, наборы, списки и очереди. Этот пример кода показывает, как скрипт PHP может использовать такие классы. Как и раньше, создайте новый скрипт PHP (например, MoreJava.php) и введите в него следующий код:

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

Теперь откройте браузер, перейдите на страницу http://localhost:8080/MoreJava.php, и вы увидите результат, показанный на рисунке 3.

Рисунок 3. Результат применения классов-коллекций Java в Web-браузере
Результат применения классов-коллекций Java в Web-браузере

Этот скрипт PHP:

  • создает экземпляр класса Java HashMap
  • сохраняет строку с текстом JavaBridge! в карте
  • демонстрирует совместимость типов 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 следующим кодом:

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

Теперь откройте браузер, перейдите на страницу http://localhost:8080/MoreJava.php, и вы увидите результат, показанный на рисунке 4.

Рисунок 4. Результат перебора коллекций Java в Web-браузере
Результат перебора коллекций Java в Web-браузере

Этот пример показывает PHP, использующий класс Java ArrayList. Кроме того, он берет итератор из ArrayList и перебирает всю коллекцию от начала до конца. Содержимое итератора записывается по порядку, начиная со строки Java Bridge!, затем следует объект Java Date и, наконец, массив PHP, содержащий пять чисел.


Обращение к статическим методам и полям

Для доступа к статическим методам и полям используется JavaClass. Этим ситуация отличается от Java, где доступ к статическим методам и полям осуществляется непосредственно по имени класса. В приведенном ниже коде показан вызов currentTimeMillis для java.lang.System:

<?php
	$system = new JavaClass("java.lang.System");
	var_dump($system);
	echo("</br>Текущее время: ".
		$system->currentTimeMillis()."</br>");
?>

На рисунке 5 показан результат работы этого скрипта в браузере.

Рисунок 5. Результат обращения к статическим методам в Web-браузере
Результат обращения к статическим методам в Web-браузере

Обращение к статическим полям выполняется аналогично. В следующем коде показано статическое поле MIN_VALUE класса java.lang.Integer:

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

На рисунке 6 показан результат работы этого скрипта в браузере.

Рисунок 6. Результат обращения к статическим полям в Web-браузере
Результат обращения к статическим полям в Web-браузере

Перехват исключений Java в PHP

Java Bridge преобразует исключения Java в экземпляры JavaException. Это универсальный класс исключений PHP, перехватываемый в скриптах PHP. Следующий фрагмент кода демонстрирует неправильный вызов getProperty для java.lang.System:

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

На рисунке 7 показан результат работы этого скрипта в браузере.

Рисунок 7. Результат перехвата ошибки Java в Web-браузере
Результат перехвата ошибки Java в Web-браузере

Заметьте, что в WebSphere sMash 1.0 метод getCause возвращает имя класса исключения Java, не вызывая само исключение. В последних версиях Project Zero эта странность была исправлена так, чтобы возвращалось реальное исключение Java.


Преобразование типов из Java в PHP

В таблице 1 показано преобразование типов Java в типы PHP. Общий подход таков: выполняется преобразование в тип, который минимизирует возможные потенциальные потери (например, при преобразовании int в byte). Заметьте также, что преобразование в равной степени применимо как к упакованным, так и к распакованным типам Java, таким как Integer и int.

Таблица 1. Преобразование типов из Java в PHP
Тип Java Тип PHPПримечания
nullnull 
Integer/intint 
Double/doubledouble 
Boolean/booleanbool 
Byte/byte int 
Character/charint 
Short/shortint 
Long/longint 
Float/floatdouble 
byte[]string 
Stringstring Строка PHP кодируется во время исполнения.
MaparrayТипы отдельных элементов преобразуются в соответствии с этой таблицей, включая вложенные карты.
Object[]array См. преобразование массива.
Прочее неприменимо Упаковывается в Java Bridge и становится универсальным объектом PHP.

Дополнительная информация о преобразовании типов доступна на Web-сайте Project Zero.


Ограничения Java Bridge

Среда Java Bridge предназначена для упрощения использования классов Java в скриптах PHP. Учитывая это, давайте рассмотрим несколько более продвинутых возможностей, которые в ней отсутствуют. Наиболее существенной из них является возможность надежного вызова перегруженных методов.

Java Bridge выбирает метод или конструктор исключительно по числу переданных аргументов. Если существует несколько возможных вариантов, Java Bridge выбирает первый из них и пытается его применить. Это очень упрощенный подход, приводящий к исключительным ситуациям при вызове метода или конструктора с неправильными типами аргументов.

Выбор перегрузок с помощью сигнатурs

Проблема выбора подходящей перегрузки решена в последних версиях Project Zero (в WebSphere sMash 1.0 это решение недоступно) путем добавления нового класса JavaSignature. JavaSignature позволяет скрипту точно указать, какой используется конструктор или метод, определяя типы аргументов для поиска:

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

	var_dump($string->toLowerCase());
	var_dump($string->split(" "));
	var_dump($string->toUpperCase());
?>

Аргументы для 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 (JAVA_STRING). Несколько аргументов разделяются запятыми, например, newJavaSignature(JAVA_STRING, JAVA_INT). Вы можете указать массив типов Java с помощью модификатора JAVA_ARRAY. Например, следующее выражение выбирает массив строк: newJavaSignature(JAVA_STRING | JAVA_ARRAY).

Следующий фрагмент кода показывает, как JavaSignature выбирает перегрузку метода valueOf для java.lang.String. Заметьте, что сигнатура передается в виде первого аргумента при вызове метода. 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 в приведенном ранее примере выглядела довольно громоздко и не так выразительно, как в случае оператора foreach в PHP. В настоящее время Java Bridge не содержит итераторов Java и оператора PHP foreach. Приведенный ниже код демонстрирует применение итераторов Java в PHP:

$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 на 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.jar и lucene-demos-2.2.0.jar.

Теперь нужно написать скрипт PHP, создающий поисковый индекс для Lucene:

  1. С точки зрения Java нужно создать новое приложение, выбрав пункт меню File -> New -> Other (Файл -> Создать -> Прочее). Выберите WebSphere Smash PHP Application (приложение WebSphere Smash PHP) и назовите его Lucene.
  2. Щелкните правой кнопкой на папке public и выберите New -> File (Создать -> Файл).
  3. Дайте файлу имя index.php и щелкните Finish (готово).
  4. Скопируйте два упомянутых выше файла Lucene JAR в директорию Lucene/lib.
  5. Чтобы заставить WebSphere sMash использовать библиотеки Lucene Java, щелкните правой кнопкой на имени проекта Lucene и выберите WebSphere sMash Tools -> Resolve(WebSphere sMash Tools -> Разрешить).
  6. Добавьте в файл следующий код:
    <html>
    <head>
       <title>Search Index</title>
    </head>
    <body>
    	<form name="input" action="/index.php" method="POST">
    		<label for="directory">Директория:</label>
       	    <input type="text" name="directory">
    		<label for="extension">Расширение файла:</label>
        	<input type="text" name="extension">
          	<input type="submit" name="action" value="Индекс!">
       	</form>   
    </body>
    </html>
  7. Запустите приложение, для чего щелкните правой кнопкой на имени проекта Lucene и выберите WebSphere sMash Application -> Run. (WebSphere sMash Application -> Запустить). Откройте в Web-браузере локальный сервер, например, http://localhost:8080/index.php. Вы увидите примерно такую страницу, которая показана на рисунке 8.
    Рисунок 8. Страница выбора директории и расширения файла
    Страница выбора директории и расширения файла
  8. Не пытайтесь пока что-нибудь индексировать, поскольку мы еще не добавили весь необходимый код. В итоге, когда форма будет передана, скрипт PHP создаст поисковый индекс Lucene и занесет в него все файлы в директории, имеющие указанное расширение. Кроме того, он просмотрит все вложенные директории и добавит файлы из них.
  9. Теперь добавим в index.php следующий код PHP: index.php:
    <?php
    
    $directory = dirname(__FILE__)."/../index";
    if (file_exists($directory) === FALSE) {
    	mkdir($directory);
    }
    
    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 "Создать индекс не удалось [".
    	$exception->getMessage()."]</br>";	
    }
    ?>
  10. Не запускайте пока этот код, потому что он еще не закончен! Этот код берет переменные формы из глобального контекста и проверяет, заполнены ли они. Если они заполнены, он вызывает функцию index_directory. Эта функция (которую мы поясним ниже) отвечает за добавление совпадающих файлов в поисковый индекс Lucene.
  11. Теперь добавим в index.php следующий код PHP:
    /**
     * Это код создает индекс с нуля и добавляет все документы,
     * перебирая все директории, начиная с указанной. Также он проверяет
     * каждый потенциально подходящий файл на совпадение с указанным расширением.
     */
    function index_directory($path, $extension) {
        	echo "Индексация! [".$path.",".$extension."]</br>";
        	
    	// Используем SimpleAnalyzer, поскольку собираемся сравнить
    	// производительность с реализацией Lucene на PHP в
    	// системе Zend Framework, а он больше всего на нее похож
    	$analyser = new Java("org.apache.lucene.analysis.SimpleAnalyzer");
    	$policy = new Java("org.apache.lucene.index.KeepOnlyLastCommitDeletionPolicy");
    	
    	$file = new Java("java.io.File", INDEX_DIRECTORY, FALSE);
    	$file_directory = new JavaClass("org.apache.lucene.store.FSDirectory");
    	$directory = $file_directory->getDirectory($file);
    	
    	$writer = new Java("org.apache.lucene.index.IndexWriter", 
    		$directory, TRUE, $analyser, TRUE, $policy);
    	
    	$writer->setUseCompoundFile(FALSE);
    
    	// Для сравнения вставляем вызовы функции microtime()
    	$start_time = get_microtime();	
    	recursive_index_directory($writer, $path, $extension);
    	$count = $writer->docCount();
    
    	// По умолчанию Lucene сопоставляет только 10000 первых лексем
    	$writer->setMaxFieldLength(1000000);
    	$end_index_time = get_microtime();
    	
    	$writer->optimize();
    	$end_time = get_microtime();
    	$writer->close();	
    	
    	echo "Индексирование завершено [".$count." documents]</br>";
    	$t1 = $end_index_time - $start_time;
    	$t2 = $end_time - $end_index_time;
    	echo "Время индексации  = $t1 </br>";
    	echo "Время оптимизации = $t2 </br>";
    }

    Подробное пояснение работы Java Lucene API выходит за рамки этой статьи. В двух словах, этот код создает объект IndexWriter. Это ключевой индексирующий объект, к которому добавляются файлы по мере того, как скрипт просматривает вложенные директории. Обратите внимание, что можно выполнить индексацию по многим разным источникам, например, по виртуальному диску. В данном примере файлы индексируются в обычной файловой системе, поэтому используется класс FSDirectory.

    После создания IndexWriter скрипт вызывает функцию recursive_index_directory, которая, собственно, и выполняет индексацию. Эта функция передает IndexWriter, который представляет директорию, с которой надо начинать поиск, и расширение, по которому выбираются файлы.

    Следующий фрагмент кода завершает скрипт индексирования. Большая часть этого кода представляет собой скрипт PHP общего назначения, который перебирает все файлы в директории и по очереди их обрабатывает. Как только он находит файл, подлежащий индексации, он создает FileDocument, который создается с полным путем к файлу и затем добавляется в IndexWriter.
    /**
     * Обрабатывает файл, добавляя его к индексатору.
     */
    function index_file($writer, $path) {
    	echo "Индексация файла  [".$path."]</br>";
    
    	try {		
    		// Имена некоторых файлов, которые мы индексируем в данном 
    		// примере, содержат символы, не входящие в UTF-8, поэтому мы  		
            // такие файлы будем пропускать!
    	
    		$file = new Java("java.io.File", $path, FALSE);
    		$file_document = new JavaClass("org.apache.lucene.demo.FileDocument");
    		$document = $file_document->Document($file);
    		$writer->addDocument($document);
    
    	} catch (JavaException $exception) {
    		echo "Недопустимые символы в имени файла!\n";
    	}	
    }
    
    function get_microtime(){
    	list($part_one,$part_two) = explode(' ',microtime());
    	return ((float) $part_one + (float) $part_two);
    }
    
    /**
     * Индексация всех соответствующих файлов (по расширению) в дереве папок. 
     */
    function recursive_index_directory($writer, $path, $extension) {
        echo "Индексация директории [".$path."]</br>";
    	
        // Сначала удаляем последний слеш
        if (substr($path, -1) == '/') {
            $path = substr($path, 0, -1);
        }
        
        // Проверка допустимости этой директории
        if (is_dir($path) == TRUE) {
    	    if (is_readable($path) == TRUE) {
    		 $handle = opendir($path);
    		
    		  // Сканируем содержимое директории
        		  $extension_length = strlen($extension);
    		  while (FALSE !== ($item = readdir($handle))) {
    		    if ($item != '.') {
    		        if ($item != '..') {
    		        $index_path = ($path.'/'.$item);
    		        if (is_dir($index_path) == TRUE) {
    		             recursive_index_directory(
    			        $writer, $index_path, $extension);
    		   } else {
    
    		         $position = strpos(strtolower($index_path), $extension);
    		                	
    		         // Очень грубый, но эффективный способ проверки расширения!
    		         if ($position == (strlen($index_path)-$extension_length)) {
    			  index_file($writer, $index_path, $extension);
    		                	}
    		                }
    		            }
    		        }
    		    }		
    		    closedir($handle);
    	    }
        }
        return TRUE;
    }
  12. Откройте скрипт в Web-браузере и заполните переменные формы, как показано на рисунке 9.
    Рисунок 9. Результат индексации директории в Web-браузере
    Результат индексации директории в Web-браузере
  13. Нажмите кнопку Index!, и скрипт проиндексирует выбранные файлы. В приведенном выше примере скрипт выполняет поиск файлов с исходным кодом на языке C и индексирует пять таких файлов. Теперь, если обновить директорию проекта Eclipse, вы обнаружите новую директорию с именем Index. Эта директория содержит созданные поисковой системой Lucene индексные файлы, как показано на рисунке 10.
    Рисунок 10. Структура директорий приложения WebSphere sMash
    Структура директорий приложения WebSphere sMash

Последним шагом будет написание формы, которая позволяет выполнять поиск по индексу:

  1. Щелкните правой кнопкой на папке public и выберите New -> File(Создать -> Файл).
  2. Дайте файлу имя search.php и щелкните Finish (готово).
  3. Добавьте в файл следующий код:
    <html>
    <head>
       <title>Query</title>
    </head>
    <body>
    	<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!">
       	</form>   
    </body>
    </html>
  4. Запустите скрипт, и в Web-браузере появится страница, похожая на ту, что показана на рисунке 11.
    Рисунок 11. Страница запроса поиска
    Страница запроса поиска
  5. Теперь добавьте в search.php следующий код PHP:
    <?php
    
    /**
     * Эта программа выполняет поиск по ранее созданному индексу.
     */
    function search_index($path, $query) {
    	echo "Поиск [".$query."]</br>";
    
    	$file = new Java("java.io.File", $path, FALSE);
    	$file_directory = new JavaClass("org.apache.lucene.store.FSDirectory");
    	$directory = $file_directory->getDirectory($file);
    	$searcher = new Java("org.apache.lucene.search.IndexSearcher", $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>Поиск окончен [".$count." совпадений]</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 "Ошибка поиска по индексу [".$exception->getMessage()."]</br>";	
    }
    ?>

    Как и раньше, этот скрипт использует несколько классов Lucene. Особенность этого скрипта в том, что вместо класса IndexWriter, как было в index.php, он использует IndexSearcher, который создается в той же директории, где ранее были созданы индексные файлы. Строка, введенная пользователем в эту форму, используется затем для создания объекта запроса. Класс QueryParser из Lucene предоставляет простой способ анализа строки запроса.

    Проанализировав запрос, скрипт готов выполнить поиск в IndexSearcher. Этот поиск возвращает список совпадений, которые скрипт перечисляет, показывая путь для каждого пункта.
  6. Откройте в Web-браузере search.php и введите какие-нибудь условия поиска, как показано на рисунке 12.
    Рисунок 12. Результат выполнения поиска в Web-браузере
    Результат выполнения поиска в Web-браузере

В этом примере было найдено пять совпадений с ключевыми словами "TSRM" и "int". Lucene имеет мощный синтаксис запросов, который поддерживает широкий диапазон критериев поиска. Подробную информацию о возможных запросах можно найти на сайте Apache Lucene.

Сравнение производительности

Если вы внимательно читали исходный код, который мы добавили в index.php, вы заметили несколько вызовов функции microtime и несколько комментариев, показывающих, что мы хотим проверить производительность.

Выполняемые нами проверки представляют собой простые проверки временных интервалов. Мы хотим сравнить время, уходящее на создание индекса с помощью трех разных программ:

  • Реализация Lucene на языке Java, которая вызывается через WebSphere sMash Java Bridge.
  • Java Lucene, вызываемый из приложения Java.
  • Реализация Lucene на языке PHP в Zend Framework.

Чтобы сравнение было объективным, мы использовали Lucene версии 2.2.0, на который опирается реализация Zend. Также мы использовали Lucene SimpleAnalyser. Подробное обсуждение реализации Zend выходит за рамки этой статьи. Тем не менее она представляет собой весьма близкое к оригиналу воспроизведение кода Lucene и генерирует индексы, формат которых совпадает с форматом, генерируемым версией на Java.

Для сравнения производительности мы проиндексировали все тестовые скрипты PHP (файлы *.phpt) в дереве папок исходного кода PHP 5.3. Время, затраченное на создание и оптимизацию индекса, показано в таблице 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 или, вернее, на запуск PHP на виртуальной машине Java VM.

Разумеется, существуют и другие мосты между PHP и Java. Например, имеется коммерческая реализация на платформе Zend и реализация с открытым исходным кодом от sourceforge.net. И хотя мы не использовали эти реализации, сам факт их существования дает дополнительные аргументы в пользу применения Java там, где этот язык эффективен (алгоритмическая производительность), в сочетании с удобством использования PHP.

Если вы повторите эти эксперименты, вы можете заметить небольшие различия в созданных индексах. Одной из полезных особенностей реализации Zend является то, что она создает индексы в том же формате, что и реализация Java, поэтому их можно проверять с помощью стандартных инструментов Java (например, Luke, который можно загрузить с сайта Luke site). Эти различия довольно просто объяснить, и они не влияют на сравнение скорости. Например, имеются небольшие различия между анализаторами PHP и Java.


Заключение

В этой статье вы:

  • Создали приложения в PHP и WebSphere sMash
  • Использовали Java Bridge для создания и применения объектов Java.
  • Узнали, как использовать коллекции Java из скриптов PHP.
  • Узнали, как Java Bridge выполняет приведение типов и обрабатывает исключения.
  • Разработали поисковую систему на основе библиотек Java Lucene.
  • Оценили производительность библиотек Java Lucene.

Теперь, по прочтении этой статьи, вы сможете шире применять библиотеки Java и скрипты PHP. Почему бы не объединить какие-нибудь еще библиотеки Java с PHP в WebSphere sMash? Поделитесь результатами вашей работы на форумах Project Zero. Если вы хотите узнать больше о Zero Global Context и других родственных темах, загляните в Справочник разработчика WebSphere sMash, упомянутый в разделе Ресурсы.

Благодарности

Авторы хотят выразить благодарность Навину Ноэлу Джакамсетти (Naveen Noel Jakkamsetti) из ZSL Inc. за помощь в написании этой статьи.

Ресурсы

Научиться

  • Оригинал статьи: Integrating Java and PHP in WebSphere sMash.
  • Прочтите статью Приступаем к работе с Project Zero, WebSphere sMash и PHP и узнайте, как загрузить WebSphere sMash и создать приложение на PHP.
  • Если вы хотите присоединиться к сообществу Project Zero или просто хотите быть в курсе событий, посетите сайт Project Zero, где вы найдете блоги, форумы и сообщество коллег-разработчиков.
  • Ознакомьтесь с документацией WebSphere sMash, содержащей все относящиеся к этому проекту документы, в том числе часто задаваемые вопросы, учебники и демонстрационные ролики.
  • Прослушайте интервью и обсуждения с техническим директором WebSphere Джерри Куомо (Jerry Cuomo), удостоенного почетного звания IBM Fellow, который излагает свои взгляды на WebSphere sMash и его влияние на разработку Web 2.0.

Получить продукты и технологии

  • Подробные инструкции по загрузке и установке WebSphere sMash для PHP можно найти на сайте Project Zero.

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=WebSphere, Технология Java
ArticleID=823892
ArticleTitle=Интеграция Java и PHP в WebSphere sMash
publish-date=07022012