Beim ersten Hinsehen könnte man sich zur Aussage hinreisen lassen, dass PHP und Java auf Grund Ihrer Architektur in klarer Konkurrenz stehen. PHP als eine Skriptsprache, welche aus der Praxis gewachsen ist, Java als Sprache, die eine konsequente OOP Architektur beherbergt. PHP wird aufgrund der rudimentären OOP Unterstützung oft von der Java Gemeinde belächelt, die den hohen akademischen Anspruch Ihrer Sprache hervorheben wollen. Dabei liegen die jeweiligen Vorteile der Sprachen klar auf der Hand. Durch den großen Funktionsumfang und Komfort, die Nähe zur Praxis und einem vergleichsweise geringem Lernaufwand bietet PHP gerade für Einsteiger in die Welt der Webprogrammierung ideale Voraussetzungen. Aber nicht nur dieser Zielgruppe, sondern auch erfahrenen Entwicklern, bietet diese Skriptsprache ein leistungsfähiges Werkzeug, welches in vielerlei Hinsicht eine geeignete Basis für die Implementierung von Webprojekten ist. Oder würde etwa ein Entwickler, der beide Sprachen beherrscht ein Gästebuch mit Java entwickeln wollen? Wahrscheinlich genauso wenig, wie er eine mehrschichtige Architektur mit PHP realisieren würde (bzw. könnte). Denn wird es einmal komplizierter, kann man die Stärken von Java Servlets und Java Server Pages (JSP) erst richtig ausspielen. Java Server Pages wird als neuer Stern am Himmel der Webprogrammierung angepriesen. JSP und Servlets bestechen durch Portierbarkeit, Sicherheit und Effizienz. Durch JSP ist es nun nicht mehr notwendig Klassen bei kleinen Änderungen zu übersetzen. Ebenfalls kann die Trennung von HTML und Programmlogik durch dessen Einsatz einfach gelöst werden. Hinsichtlich Effizienz sollte man aber genauere Betrachtungen durchführen. Recherchiert man im WWW merkt man schnell, dass es sich um ein heisses Thema handelt und es kommen ganz unterschiedliche Meinungen zu Tage. Ein Vergleich der Performance dieser Techniken wird oft nicht richtig erörtert. Vorher muss man viele Faktoren berücksichtigen. Es hängt sicherlich von den verwendeten Komponenten, wie Webserver, Servlet Engine, Systemhardware, Betriebsystem, virtuelle Maschine (JVM) und Auslastung des Servers ab, um nur einige zu nennen. Bei Servlets läuft die virtuelle Maschine einfach immer weiter und behandelt jede Anfrage mit einem Java-Thread, anstatt mit einem Betriebsystemprozess. Dies spart den Overhead einen Prozess zu starten, belegt aber permanent Speicher. Sind viele Seiten auf einem Server hinterlegt, könnte es hierdurch auch Engpässe bei den Speicherressourcen geben. Hinzu kommen die Einbusen der virtuellen Maschine. Bei PHP gibt es die Betriebsmöglichkeiten, als CGI-Modul, dynamisch geladenes Modul oder eingebettetes Modul in den Webserver. Die Einbindung als CGI-Modul ist schon aus Performancegründen nicht zu empfehlen. Ein PHP-Skript wird bei jedem Aufruf neu kompiliert, es sei denn man verwendet 'PHP caching products‘. Die Seite PHPeveryWhere beschreibt einige Tuningtips rund um dieses Thema.
Eine Aussage zu treffen, welche Technik die performantere ist, wage ich aus diesen Gründen nicht zu machen.
...und dazwischen?
Die Frage, welche Technik für welchen Anwendungsfall ausgelegt ist, klärt sich durch obige Betrachtungsweise. Was ist aber wenn man mit seinen Zielen irgendwo dazwischen liegt? Java und PHP könnten sich hier durchaus sinnvoll ergänzen. PHP bietet ab der Version 4 die Möglichkeit Java-Klassen zu instanziieren. Dieser Artikel soll allen PHP Entwicklern, welche sich bisher gescheut haben die Implementierung von Webprojekten mit Hilfe von Javaklassen vorzusehen, einen kleinen Einstieg bieten. Ich möchte nicht, wie es sonst häufig üblich ist, ein typisches 'Hello World' Beispiel vorstellen. Die Vorteile, die Java bieten kann, werden dabei wohl kaum deutlich werden. Um den Rahmen aber nicht zu sprengen, will ich auch nur einen kleinen Seitenzähler detailliert aufbauen. Viele werden sich nun Fragen, was hier denn eigentlich nun von Vorteil sein könnte. Dies liegt in der Persistenz eines Java Objektes in der Servlet Engine, sowie einer Kapselung und damit Wiederverwendbarkeit des Zählerobjektes. Letzteres könnte man natürlich in PHP auch durch die Einbettung eines Skriptes mit dem Befehl 'require' erreichen. Entscheiden soll jeder selbst, wem welche Technik besser gefällt. Aufgrund der Quellcodelänge wird man sich wahrscheinlich eher für den Ad-hoc Ansatz mit PHP entscheiden. Es ist schwierig mit einem kleinen Beispiel den formalen Overhead einer objektorientierten Sprache gegenüber einer Skriptsprache zu rechtfertigen. Aber wie gesagt, wird es einmal komplizierter, zeichnen sich dann doch Java's Stärken deutlich ab.
Listing 1: Der PHP Zähler:
<?
$counterfile = dirname(__FILE__)."/counter.txt";
$counter = file($counterfile);
$counter = $counter[0] + 1;
$fp = fopen($counterfile, "w");
fwrite($fp, $counter);
echo $counter;
?>
Die Funktionsweise des PHP Zählers bedarf aufgrund der kurzen Quellcodelänge auch nicht vieler Worte. Geöffnet wird eine Datei, in welcher der aktuelle Zählerstand gespeichert wird. Den ausgelesenen Stand erhöht man um den Wert 1 und schreibt ihn anschließend wieder in die Datei zurück. Den Wert gibt man zum Schluss mit dem Befehl echo zurück. Eingebunden wird dieses Skript entweder durch den Befehl require oder man kopiert es direkt in die Seite.
Listing 2: Einbettung des PHP-Skriptes in die HTML Seite
<?
require(“counter.php“);
?>
Listing 3: Der Servlet Zähler:
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class servletCounter extends HttpServlet
{
private int iZaehler = 0;
String szDatei;
public void init() throws ServletException
{
try
{
szDatei = getServletConfig().getServletContext().getRealPath("/") +
"WEB-INF/classes/zaehler.txt";
FileReader fr = new FileReader(szDatei);
BufferedReader br = new BufferedReader(fr);
String szZaehler = br.readLine();
fr.close();
iZaehler = Integer.parseInt(szZaehler);
return;
}
catch (Exception e)
{
//Fehler beim Lesen der Datei, iZaehler = 0;
}
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
iZaehler++;
PrintWriter out = response.getWriter();
out.println(iZaehler);
}
public void zaehlerSpeichern() throws IOException
{
String szZaehler = Integer.toString(iZaehler);
FileWriter fw = new FileWriter(szDatei);
fw.write(szZaehler, 0, szZaehler.length());
fw.close();
return;
}
public int getHits()
{
return iZaehler;
}
public void destroy()
{
try
{
zaehlerSpeichern();
return;
}
catch (IOException e)
{
//Fehler beim Speichern des Zaehlerstandes
};
}
}
Zur Implementierung des Servletzählers bedarf es nun einer kurzen Erläuterung der Servletkonventionen. Die Grundstruktur eines Servlets besteht aus den Methoden init, service, doXXX, destroy und getLastModified. Die init-Methode wird beim instanziieren, die destroy-Methode beim Entladen des Servletobjektes aufgerufen. doXXX (z.B. doGet, doPost, usw.) und getLastModified werden bei HTTP-Anfragen aufgerufen. Im obigen Beispiel werden die Methoden init, destroy und doGet überschrieben. Hinzu kommt noch die benutzerdefinierte Methode zaehlerSpeichern, welche beim Entladen durch die destroy-Methode aufgerufen wird und die Methode getHits, welche ausschließlich den Zählerstand zurück gibt.
Init:
Diese Methode wird, wie schon erwähnt nur beim Instanziieren des Objektes aufgerufen. Besteht eine Instanz des Servletobjektes wird diese vor HTTP-Anfragen nicht mehr behandelt. Die Funktion dieser Methode besteht aus dem Öffnen der Zählerdatei und dem Auslesen des Zählerstandes. Dieser wird in der Variable iZaehler gemerkt. Sollte die Dateioperation fehlschlagen, wird der Zählerstand mit dem Wert 0 belegt.
doGet:
doGet wird bei jeder GET-HTTP Anfrage aufgerufen. Es wird der gemerkte Zählerstand um den Wert 1 erhöht und über den PrintWriter ausgegeben (vgl. echo im PHP-Skript).
destroy:
Wird das Objekt entladen, z.B. beim Herunterfahren des Servers, speichert das Servlet den gemerkten Zählerstand in die Zählerdatei.
Eine kleine Unzulänglichkeit hat sich in diesem Beispiel eingeschlichen. Was passiert, wenn der Server abstürzt oder jemand über das Stromversorgungskabel stolpert. Der Zählerstand wäre in diesen Fällen verloren. Eine Möglichkeit bestünde den Wert des Zählers in Intervallen (z.B. nach jeder 50ten Anfrage) mit folgender Anweisung abzuspeichern:
if (zaehler % 50 == 0) zaehlerSpeichern();
Zeigen soll dieses Beispiel in erster Linie, dass bei der Initialisierung viele zeitraubende Schritte schon vor den Anfragen an den Server durchgeführt werden können, was sicherlich Zeit spart. Es handelt sich zwar hierbei nur um einen Dateizugriff, stellt man sich aber aufwendigere Initialisierungsschritte vor, wie einen ‚Datenbankconnect‘ oder Berechnungsläufe, wird es klarer.
Nun zur Einbettung des Servlet Zählers in die PHP Seite. Dies wird durch die folgende Anweisung durchgeführt.
Listing 4: Einbettung des Servlets in die PHP Seite
<?
$sys = new Java("servletCounter");
print $sys->getHits();
?>
Stefan May
|