Java / PHP Bridge


Le PHP/Java Bridge de sourceforge.net permet d'intégrer Java et PHP dans les deux sens : il permet d'appeler des classes Java depuis PHP, mais aussi d'appeler des scripts PHP depuis Java. Pour ce sens, le bridge fournit même deux techniques : appel en CGI, ou via la nouvelle technique d'appel de script de Java 6, référencée sous la JSR-223. On notera que le pont peut aussi fonctionner entre PHP et .NET ou Mono.

Ces notes ont servi de base pour la rédaction d'un article paru le numéro 6/2008 de PHP Solutions de novembre 2008.

Installation

L'environnement que je décris ci-dessous n'est qu'un exemple d'environnement compatible avec la version 5.2 du pont. Il a été testé sous Linux Ubuntu 8.04 et sous Window XP SP2 et SP3.

Environnement PHP :

Environnement Java :

Ensuite, il faut déployer JavaBridge.war dans Tomcat. Tomcat étant par défaut en mode de déploiement automatique, le déploiement se fait par copie du fichier dans son répertoire webapps/.

Intégration par CGI

On ne peut pas réellement parler d'intégration. Cette technique permet surtout de déployer des pages PHP dans Tomcat, sans avoir recours à Apache ou IIS.

JavaPhpBridgeCgi.png

Java Scripting API

La Java Scripting API, parfois connue sous le nom de sa spécification, JSR-223, définit une API permettant d'utiliser des langages de script dans une application Java. Le langage JavaScript est nativement supporté par la machine virtuelle qui intègre l'interpréteur Rhino. Le pont peut servir d'interpreteur PHP pour cette API.

Il fournit cinq modes d'intégration :

   manager.getEngineByName("php")
   manager.getEngineByName("php-interactive")
   manager.getEngineByName("php-invocable")
 // Affichage du titre
 out.println ("Essai de JSR-223 - mode Web invocable 
"); // Récupération de l'interpréteur de PHP via la méthode de fabrique ScriptEngine engine = EngineFactory.getInvocablePhpScriptEngine (this, application, request, response); // Connexion des sorties Java et PHP engine.getContext ().setWriter (out); // Déclaration de la fonction hello engine.eval ("<?php function hello ($who) {return 'Hello '.$who;}; ?>"); // Appel de la fonction hello et affichage du résultat out.println (((Invocable) engine).invokeFunction ("hello", new Object[] {"world"})); // Réinitialisation de l'interpréteur engine.eval ((java.io.Reader)null);

Pont PHP vers Java

Appeler une classe standard

 <?php 
   // Fichier des fonctions et classes PHP du pont
   require_once ("http://localhost:8080/JavaBridge/java/Java.inc"); 
   
   // Instanciation de la classe Java StringBuilder via la classe PHP Java
   $buf=new Java ("java.lang.StringBuilder");
   // Appel de la méthode append sur l'objet Java StringBuilder
   $buf->append ("Hello"); 
   $buf->append (" "); 
   $buf->append ("World"); 
   // Appel de la méthode toString sur l'objet Java StringBuilder et affichage du résultat
   echo ($buf->toString ()); 
 ?> 

A chaque appel de la page, une requête est envoyée vers Tomcat, à la servlet PhpJavaServlet de l'application JavaBridge, puis les échanges se font ensuite sur un port spécifique (entre 9267 et 9367)

JavaPhpBridgePhpJavaServlet.png

Appeler une classe personnalisée

Pour que PHP puisse utiliser des classes métier, il faut en plus que l'application puisse avoir accès aux archives jar qui contiennent leurs définitions. L'accès peut être donné côté PHP, par la fonction java_autoload, ou côté Java. Si une seule archive est utilisée, la première solution est plus pratique, et si plusieurs archives sont nécessaires, ce qui est le cas le plus fréquent, il est plus pratique de gérer leur mise à disposition du côté de Java.

 <?php 
   require_once ("http://localhost:8080/JavaBridge/java/Java.inc"); 
   // Chargement de l'archive java copiée localement
   java_autoload ("java/university.jar") ; 
   
   // Instanciation d'un objet Course
   $course=new Java ("fr.sewatech.university.model.Course", "mm-uml", "Analyse et conception avec UML"); 
   // Affichage du résultat
   echo ($course->toString ()); 
 ?>

Appeler un bean Spring

En effet, depuis plusieurs années, de nombreuses applications Java ont été développées sur ce type de framework. Que ce soit Spring ou ses concurrents, ils ont pour point commun de gérer des composants, en les instanciant et en les mettant à disposition via des noms logiques plutôt que par des noms de classes.

Pour appeler des services métier intégrés à Spring, notre application PHP doit d'abord accéder au contexte Spring avant d'accéder aux beans.

 <?php 
   require_once("http://localhost:8080/UniBridge/java/Java.inc"); 
   
   // Instanciation du contexte applicatif de Spring paramétré dans le fichier application-context.xml
   $ctx = new Java(
       "org.springframework.context.support.ClassPathXmlApplicationContext", 
       "application-context.xml"); 
   // Demande d'une référence au bean courseService inscrit dans Spring
   $service = $ctx->getBean("courseService"); 
   // Utilisation du bean
   $course=$service->findById(1); 
   echo ($course->toString()); 
 ?> 

Il faut toutefois faire attention à la gestion des librairies dépendantes. En effet, lorsque nous utilisons des composants métier intégrés à Spring, nous devons accéder aux archives métier et à des archives techniques (spring.jar, commons-beanutils.jar, commons-collections.jar,...). Nous avons trois possibilités pour rendre celles-ci accessibles :

Pour éviter les risques de conflit lorsque plusieurs applications Java sont utilisées, on peut mettre en place une quatrième technique, en intégrant le contenu de JavaBridge à chaque application Java. Chacune embarque donc son propre pont ; de plus, toutes les classes Java nécessaires à PHP sont déjà chargées par le pont, ce qui nous dispense d'appeler la fonction java_autoload. Seul le require_once doit être adapté pour charger celui de l'application Java accédée. Cette technique a été utilisée dans l'exemple précédent, ce qui explique l'absence de la fonction java_autoload.

Pour ajouter le pont à une application, il faut :