PHP è nato anni fa come semplice linguaggio di scripting; non per nulla derivava da una serie di script in Perl che avevano come unico scopo quello di facilitare il lavoro a coloro che erano intenzionati a sviluppare semplici siti web dinamici senza dover comprendere in modo approfondito quel linguaggio.
Con il tempo PHP si è voluto, aggiungendo un miglior supporto agli oggetti e fornendo una serie di funzionalità ed estensioni che lo hanno reso il linguaggio open source più utilizzato nell'ambito dello sviluppo web. Questa evoluzione ha si colmato molte lacune che gli sviluppatori lasciavano irrisolte, ma non ha sicuramente colmato tutte quelle zone in cui PHP risulta carente a livello di funzionalità ed integrazione con gli altri sistemi.
Java dal canto suo è un linguaggio molto utilizzato, con una forte utenza base che lo ha reso (prima dell'avvento di C#/.NET che gli stanno rubando un po' di mercato) lo standard de facto per le applicazioni multipiattaforma. Unire le funzionalità di questi due linguaggi non è sempre utile, ma spesso può risultare estremamente importante, soprattutto se si vuole fare uso di librerie sviluppate per Java ma di cui non si può o non si vuole fare il porting per PHP.
PHP/Java Bridge è l'estensione che fa al caso di tutti coloro che vogliano far cooperare i due linguaggi; l'estensione fornisce una serie di oggetti che permettono di istanziare da PHP classi Java e controllarne il comportamento come se fossero normali oggetti PHP, con qualche piccola eccezione. In questo articolo vedremo come installare ed utilizzare la libreria con PHP 5.
Installazione
Diversamente da molte altre estensione, PHP Java Bridge fornisce sia un'implementazione nativa sviluppata in C (che richiede l'installazione della libreria php_java.so
o php_java.dll
) sia un'implementazione in puro PHP; questo è possibile poiché la libreria utilizza un protocollo di comunicazione tra le classi Java e PHP indipendente dal linguaggio ed altamente interessante.
Purtroppo non abbiamo modo di andare nei dettagli del protocollo, ma bisogna comunque sottolineare che la versione sviluppata in puro PHP è estremamente più lenta e non adatta agli ambienti di produzione, salvo casi particolari. È necessario oltretutto specificare che da qualche tempo è disponibile anche l'estensione in una versione che permette di eseguire codice .NET, che comunque non analizzeremo in questa sede.
Per poter installare correttamente PHP/Java Bridge è necessario aver a disposizione una java virtual machine (1.3 o superiore) correttamente installata sul proprio sistema operativo ed è necessario che i file .jar/.war distribuiti con l'estensione, scaricabile dal sito del progetto, siano correttamente accessibili da questa macchina virtuale.
I passi da seguire per la compilazione dai sorgenti sono i seguenti:
- Scaricare i sorgenti dal sito internet ed estrarli all'interno di una cartella;
- Attraverso la shell, spostarsi nella cartella precedentemente estratta e digitare i seguenti comandi per la compilazione e l'installazione dell'estensione:
phpize ./configure --with-java=/usr/java/jdk1.4,/usr/java/jre1.6 make su -c 'sh install.sh'
- Specificare se si desidera installare l'estensione come componente del web server. In caso affermativo dovrà anche essere specificata la cartella di autodeploy al fine di poter condividere le sessioni tra PHP e le serverlet JSP;
Dopo aver effettuato queste semplici operazioni è possibile riavviare il server apache e testare il corretto funzionamento della libreria. Per effettuare il testing viene fornito un file (test.php
) all'interno del pacchetto sorgente scaricato precedentemente. Il file PHP può essere eseguito attraverso un normale Web server oppure utilizzando PHP-CLI dalla linea di comando. Se non vengono visualizzati particolari errori vuol dire che la libreria è stata installata correttamente ed è possibile iniziare il testing.
Utilizzare PHP/Java Bridge
Ora che la libreria è stata installata correttamente possiamo procedere con il testing e controllare alcune sue funzionalità. Come primo esempio utilizzeremo una classe fornita con la libreria standard di Java:
<?php
/* Carichiamo la classe java.lang.System all'interno di un oggetto PHP che
* utilizzeremo come bridge verso la reale classe Java
*/
$system = new Java('java.lang.System');
/* Come presentato nella documentazione ufficiale visualizziamo la data corrente
* formattata in base alle nostre esigenze.
*/
$formatter = new Java('java.text.SimpleDateFormat', "EEEE, MMMM dd, yyyy 'at' h:mm:ss a zzzz");
$date = new Java('java.util.Date');
echo "<b>Data</b>: ".$formatter->format($date)."<br />";
// Elenchiamo alcune informazioni utili
$informations = array(
'java.version',
'java.vendor',
'os.name',
'os.version',
'os.arch'
);
echo "<ul>";
foreach($informations as $information)
{
echo "<li><b>".$information."</b>: ".$system->getProperty($information)."</li>";
}
echo "</ul>";
?>
Tutto il lavoro è svolto in automatico dall'oggetto Java che ci permette di caricare classi della libreria standard specificandone il package ed utilizzandole successivamente come se fossero state scritte in PHP. Le istanze dell'oggetto Java, oltre a funzionare da bridge verso le classi specificate in fase di costruzione, permettono anche di utilizzare foreach
per iterare su le classi che implementano le interfacce java.util.Collection
o java.util.Map
e di utilizzare l'operatore [] per accedere agli elementi di un array o di una classe che implementa l'interfaccia java.util.Map
:
<?php
$ARRAY = new JavaClass("java.lang.reflect.Array");
$STRING = new JavaClass("java.lang.String");
$choices = $ARRAY->newInstance($STRING, 2);
$choices[0] = "Scelta 1";
$choices[1] = "Scelta 2";
$properties = new java("java.util.Properties");
$properties->put("os", "Debian Linux");
$properties->put("extension", "PHP-Java Bridge");
$properties->put("choice", "1");
echo "<ul>";
foreach ($conversion as $key => $value)
{
echo "<li><b>".$key."</b>:".$value."</li>";
if($key == 'choice')
echo "<li><b>Choice</b>:".$choices[intval($value)]."</li>";
}
echo "</ul>";
?>
Nell'esempio precedente abbiamo introdotto l'oggetto JavaClass che permette di caricare una classe Java al posto di istanziarla direttamente; una volta caricata la classe è possibile crearne delle istanze utilizzando il metodo newInstance
.
Alcune funzionalità avanzate
Oltre a fornire un semplice accesso diretto alle classi Java, l'estensione offre anche una serie di funzionalità parallele che permettono di integrare praticamente al 100 per cento i nostri script PHP con le librerie Java.
Una funzionalità molto importante è fornita dalla funzione java_require, che permette di aggiungere dei file Jar alla lista di quelli in cui ricercare per importare le classi richieste. La funzione in questione accetta come unico parametro una stringa contenente i file Jar da includere separati da un punto e virgola. È molto interessante la possibilità di accedere ai file Jar anche utilizzando protocolli differenti a quello per l'accesso al filesystem locale, come ad esempio HTTP o FTP:
<?php
java_require("http://www.test.it/mylib.jar;mylib2.jar");
echo new Java("mylib.MyObject");
?>
La funzione java_cast effettua un casting del valore nativo dell'oggetto passato come primo argomento al tipo di dato PHP specificato come secondo argomento; in questo modo è possibile far cooperare i due linguaggi in modo completo anche se Java è fortemente tipizzato e PHP no:
<?php
echo java_cast(new java("java.lang.String", "12345"), "integer");
echo java_cast(new java("java.lang.String", "0"), "boolean");
?>
Spesso capita che le classi utilizzate generino eccezioni su cui si vuole avere il controllo da PHP; per fare questo è necessario appoggiarsi alla classe JavaException che è stata introdotta nella libreria da quando è stato fatto il porting per PHP 5 e permette di intercettare e gestire le eccezioni generate:
<?php
$myobject = new Java("it.html.MyObject");
$MYEXCEPTION = new JavaClass("it.html.MyException");
try
{
$myobject->throwException();
}catch(JavaException $e)
{
echo "Eccezione: ".java_cast($e, "string")."<br/>";
$trace = new Java("java.io.ByteArrayOutputStream");
$e->printStackTrace(new Java("java.io.PrintStream", $trace));
echo "<pre>".$trace."</pre>";
$cause = $e->getCause();
if(java_instanceof($cause, $MYEXCEPTION))
{
die("My Exception raised!");
}
}
?>
Le eccezioni possono quindi essere gestite e manipolate normalmente aggiungendo solamente un po' di codice necessario a garantire l'interoperabilità tra le parti. Nell'esempio precedente abbiamo anche introdotto la funzione java_instanceof che controlla che un oggetto Java sia l'istanza della JavaClass passata come secondo argomento.
Conclusioni
Siamo arrivati alla fine di un articolo che ritengo molto interessante, soprattutto nell'ottica di rendere il lavoro più semplice a tutti coloro i quali vogliano sfruttare librerie già fatte in Java (come Lucene ad esempio) ma non abbiano intenzione di fare la conversione di queste a PHP. A questo proposito ricordo che la libreria PHP/Java Bridge permette di effettuare automaticamente la conversione da classi Java e PHP rendendo disponibili tutti i metodi pubblici e le proprietà usando il comando:
java -jar JavaBridge.jar --convert DEST_DIR PACKAGE.jar.