Zend Engine 2 - Leistungsmerkmale, Geschichte und Designmaximen

Generationenwechsel
Kommentare

Ein Evolutionssprung respektive Generationenwechsel bahnt sich innerhalb von PHP4 an. Der Sprung vom PHP3- zum PHP4-Paradigma mit einer verbesserten Modularität des Basiscodes (Zend Engine 1) war revolutionär. Mit der Veröffentlichung der Zend Engine 2 Ende 2002 soll PHP5 aber endlich Akzeptanz erlangen und den gewachsenen Ansprüchen im Business- bzw. Enterprise-Markt gerecht werden, um nicht nur im Low-End-, sondern auch im High-End-Sektor mitmischen zu können. Wenn von der Zend Engine 2 gesprochen wird, ist indirekt schon fast synonym die Rede von PHP5, da die meisten Änderungen dieses Versionssprungs durch die Änderungen am Sprachkern (Zend Engine) verursacht werden. Die Zend Engine 2 leitet eine neue Generation ein, wobei das Hauptaugenmerk auf der Implementierung essenzieller Sprachelemente und einer verbesserten objektorientierten Verhaltensweise liegt, die durch eine bessere sowie schnellere OO-Unterstützung glänzt und damit eine einfachere Codepflege und Wartung von Webapplikationen in PHP5 ermöglicht.

Historischer Rückblick

Um den revolutionären Versionssprung der Zend Engine 2 und dessen Bedeutung nachzuvollziehen, werde ich nachfolgend wesentliche Etappen auf dem Weg zur Zend Engine 2 skizzieren, um Ihnen eine Einführung zur Absicht und Notwendigkeit des verbesserten OO-Modells zu vermitteln. Im Frühstadium von PHP, besser gesagt in den ersten veröffentlichten Versionen von PHP/FI und PHP/FI 2.0 bis einschließlich PHP3, war PHP intern nicht mehr als ein monolithischer Interpreter. In dieser Zeit war die starke Erweiterungsmöglichkeit gekoppelt mit einer soliden Infrastruktur ein Schlüssel zum gewaltigen Erfolg von PHP3. Unter dem monolithischen Interpreter kann man sich ein Programm vorstellen, welches kontinuierlich jede Zeile im Programmcode abarbeitet und diese ausführt. Da dies aber keinesfalls einer hochperformanten und zufriedenstellenden Lösung entsprach und der Quellcode von PHP3 zunehmend größer wurde, aber kein sinnvoller Ansatz zur Optimierung und Integration neuer Funktionen existierte, war keine konsequente Weiterentwicklung von PHP gewährleistet. In dieser Zeit setzten sich die beiden Informatik-Studenten Andi Gutmans und Zeev Suraski, die bereits PHP3 mit der Bezeichung Zend Engine 0.5 schrieben, ein Ziel; sie wollten PHP eine grundlegend neue Architektur verschaffen. In einer der ersten Zend Engine [1] Varianten konnte man einen Paradigmen-Sprung vom alten Execute-while-Interpreting (PHP3) zum Compile-first/Execute-later (PHP4) Interpretationsvorgang ausmachen. Da PHP3 trotz flexibler Ausrichtung keinen der beiden befriedigen konnte, wurde der Interpreter modular aufgeteilt, was eine Abgrenzung der einzelnen Aufgabengebiete (Parser, Ressourcenverwaltung, Skriptausführung) mit sich brachte und den Startschuss für die Zend Engine 1.0 respektive PHP4 gab. Kurz und knapp könnte man die Zend Engine als Mittelpunkt all dieser Module charakterisieren, sozusagen als Herzstück von PHP, welche die grundlegenden Sprachelemente bereit stellt und sich um die konsistente und korrekte Zusammenarbeit der einzelnen Module und PHP-Extensions kümmert.

Ansprüche, Akzeptanz und Reaktionen

In den letzten Jahren hat PHP einen rasanten Wandel vollzogen. Vom einstigen PHP/FI Form Interpreter versucht PHP zunehmend in Bereiche vorzustoßen, in denen die Enterprise-Tauglichkeit eine immer größer werdende Rolle spielt. Bei der Entscheidung zum Enterpriseeinsatz spielen Faktoren wie Robustheit der Architektur, Skalierbarkeit und Modularität eine bedeutende Rolle, wobei PHP im Vergleich zu etablierten Sprachen (Java, ASP, JSP) erst aufschließen muss. Die Popularität von PHP ist rapide gestiegen und dies hat verschiedenste Erfolgsfaktoren. Bei derzeitig sieben Millionen Installationen und einer stetig steil steigenden Erfolgskurve ist PHP an einem Punkt angelangt, an dem ein entscheidender Schritt in Richtung Zukunft ansteht und sich zunehmend verschiedene Gruppierungen und zwiespältige Stimmungen innerhalb der Zielgruppen pictureen. Teilweise kam man zu der Vermutung, dass PHP keine feste Vision vor Augen hat, also kein klares Ziel, in welche Richtung sich die Sprache weiterentwickeln soll. Auf der einen Seite verspürt PHP zunehmend die Notwendigkeit zur Verbesserung des Objektverhaltens und der Implementierung weiterer objektorientierter Eigenschaften und zusätzlicher Funktionalitäten am Sprachkern, die man von etablierten OO-Hochsprachen wie Java [2] oder C++ kennt. Der Druck seitens professioneller bzw. erfahrener Programmierer wächst diesbezüglich zunehmend. Diese fordern eine Überarbeitung der Zend Engine, um weitere Akzeptanz zu gewinnen und um bei den Forderungen im Enterprise-Marktsektor bestehen zu können, die beiläufig die Umsetzung von unternehmenskritischen Applikationen mit sich bringen. Zusätzlich wird die Erschließung von Bereichen fokussiert, für die man bisher eher Programmiersprachen wie Java eingesetzt hat, jetzt aber auch PHP zum engeren Entscheidungskreis hinzuzählt. Auf der anderen Seite kommen in diesem Zusammenhang allerdings zwei wesentliche Dinge zum Vorschein. PHP ist von Natur aus eine sehr einfache Sprache mit simpler Syntax und Semantik und einer sehr flachen Lernkurve, was für die wachsenden Marktanteile von PHP spricht und Quereinsteigern und Anfängern einen optimalen Einstieg gewährleistet. Man könnte die Einfachheit der Open Source-Sprache auch für ein wesentliches Überlebenskriterium von PHP überhaupt halten. Deswegen ist das teilweise eher konservative und zurückhaltende Verhalten der Kernentwickler sehr gut nachzuvollziehen, da die Zukunftsvisionen zu sehr auseinander driften. Trotz der bekannten historisch bedingten Designschwächen, die auf ein nicht wohlüberlegtes Language-Design zurückzuführen sind, können die Kernentwickler nicht von heute auf morgen einen Schnitt begehen und PHP somit zu einer vollständig an Java ausgerichteten OO-Sprache formen oder PHP5 so systemnah wie Perl gestalten. Dieses Spannungsfeld zwischen den beiden Gruppen mit verschiedenen Zukunftsansichten, bestimmte in den letzten Monaten wesentlich die Diskussionen auf der eigens eingerichteten Zend Engine 2 Mailingliste [3] und beeinflusste auch den Entwicklungszyklus. Die Syntax soll auch weiterhin einfach zu verstehen bleiben, andererseits sollen die Wünsche ambitionierter Programmierer berücksichtigt werden, eine äußerst prekäre Konstellation. PHP besitzt grundlegend alles, was eine Web-basierte Skriptsprache benötigt. Für viele reicht diese Ausrichtung auf Software-Lösungen im Web-basierten Umfeld allerdings nicht aus. Am Bereich der Enterprise-Lösungen sollte sich PHP aber nicht ausschließlich orientieren. Die dynamische Ausrichtung der Sprache ist einer der Pluspunkte und Gründe des Erfolgs, welcher zwangsläufig zur Effizienzsteigerung aufgrund der kurzen Entwicklungszeiten beiträgt. Es macht deshalb keinen Sinn, PHP zu einer vollständig strikt typisierten Programmiersprache analog zu C#, C++ oder Java zu formen, da es dafür einfach nicht konzipiert wurde.

Genereller Überblick über die Zend Engine 2

Die Zend Engine 2 ist ein Versuch, trotz der zuvor erwähnten Designschwächen von PHP, PHP5 für den Einsatz im Enterprise-Sektor konkurrenzfähig zu gestalten und einzugliedern. Sicherlich wurde PHP auch schon vorher von Firmen gezielt eingesetzt, aber die Unterstützung in punkto Zuverlässigkeit und Sicherheit, die eine Programmiersprache geben sollte, war keineswegs zufriedenstellend ausgeprägt. In der folgenden Übersicht befinden sich alle Kernbestandteile der Änderungen an der Zend Engine 2.0 [5], die sich momentan allerdings noch im Entwicklungsstadium befinden. Somit sind wohl noch einige Features vor der letztendlichen Veröffentlichung von PHP5 zu erwarten. Das gesetzte Ziel fokussierte sich primär auf eine verbesserte OO-Unterstützung und die Implementierung neuer Konstrukte, um das OO-Design zu erleichtern. In den folgenden Passagen werde ich detailliert auf die einzelnen unten aufgeführten Features eingehen und jeweils ein Quellcode-Listing zur Veranschaulichung hinzufügen.

Features der Zend Engine 2

  • Exception Handling
  • Built-in Backtracing
  • Namespaces/Nested Classes
  • Verbesserte OO-Verhaltensweise
  • Implizite Referenzierung von Objektinstanzen
  • Optimierter Objektrückgabemechanismus
  • Object Cloning
  • Konstruktoren & Destruktoren
  • Datenkapselung
  • Objekt-Dereferenzierung

Das Exception Handling ist ein bedeutsames Merkmal der Zend Engine 2 und stellt den Mechanismus zur Verfügung, um Ausnahmefälle (Fehler) von sensiblen Codeabschnitten innerhalb von PHP5 abzufangen und zu behandeln. Mit diesem Feature kann man endlich von einer sauberen und eleganten Methode reden, die es erlaubt, fehleranfälligen Programmcode zu kapseln und somit die Wiederherstellung bei Fehlern stark zu vereinfachen. In PHP4 existierte in diesem Zusammenhang keine native Methode, um Ausnahmebedingungen während der Programmausführung zu behandeln und man war somit zwangsläufig an viele Schachtelkonstruktionen mittels if/else gezwungen, die einen übersichtlichen und lesbaren Programmcode sichtlich behinderten. Das in Java populär gewordene Exception Handling und die daran angelehnte Methode setzt genau an dieser zuvor erwähnten Problematik effizient an und offenbart sehr elegante Werkzeuge, um Ausnahmebedingungen zu verarbeiten und somit den Programmcode übersichtlicher, strukturierter und logischer zu gestalten. Man weiß im Voraus, wie man auf jede Situation reagieren kann und besitzt des Weiteren die Kontrolle darüber, Ausnahmefälle differenziert und gesondert auf bestimmte, selektierte Codepassagen anzuwenden, die an einem Ort platziert sind und durch das Exception Handling unter besonderer Bewachung stehen. Unter Exceptions versteht man grundsätzlich ein Signal, welches innerhalb der Software, im Falle einer Ausnahmebedingung bzw. bei einem Fehler, auftritt. In diesem Kontext gibt es ein paar Exception-Anweisungen, die von zentraler Bedeutung sind. Im Falle eines Fehlers wird eine Exception erzeugt (throw), um eine Ausnahmebedingung während des Programmablaufs zu signalisieren bzw. auszulösen. Um diese Ausnahmebedingungen nachfolgend gesondert zu behandeln, benötigt man die Anweisung (catch), mit der man den Fehler abfängt. Das Ziel dieser Methode ist im Allgemeinen nichts anderes, als alle Aktionen durchzuführen, die den normalen konsistenten Zustand der Software wieder herstellen. Eine weitere auch aus Java bekannte Block-Anweisung finally wurde nicht für die Implementierung vorgesehen, weil sich die Implementierung schwieriger als erwartet gestaltet hatte und außerdem diesbezüglich keine unbedingte Notwendigkeit bestand. Grundsätzlich erfüllt der finally Block die Aufgabe, jegliche Anweisungen inmitten des Blocks garantiert auszuführen, unabhängig vom Status des beendeten try Blocks, der normalerweise vorher gesetzt wird. Ein typisches Szenario des Exception Handlings wäre ein durch try gekapselter Codeabschnitt, der bei einem Ausnahmefall mittels throw eine Exception erzeugen würde. Nachfolgend würde der Programmablauf gestoppt und nach dem passenden catch Konstrukt gesucht werden, welches für die Behandlung der jeweiligen Ausnahmebedingung vorgesehen ist. catch versucht mit allen Mitteln, das Programm wieder in einen ausführbaren Zustand zu bewegen. Einen idealen Einsatzzweck pictureen neben jeglichen sensiblen oder fehleranfälligen Codepassagen jede Transaktions- oder Datenbank-basierte Anwendung.

Listing 1

message;
}

// ... class constructor and methods
function __construct($host = 'localhost', $user = 'root', $pass = '') {
$this->connect($host, $user, $pass);
}

function connect($host, $user, $pass) {
// try to connect to database

throw new Database::Exception('Could not connect to database.');
}
}

try {
$DB = new Database;
$DB->query(...);
}
catch (Database::Exception $e) {
print 'Database error: ('. $e->getMessage() .')';
}
?>

Das Backtracing ist eine äußert nützliche Eigenschaft der neuen Zend Engine 2, welche unmittelbar an das Exception Handling anknüpft und im besten Fall während des throw Statements aufgerufen werden sollte. Es stellt die Fähigkeit bereit, die durch die Exception ausgelösten Ausnahmebedingungen bzw. Fehler zu präzisieren, eine Liste der Funktionsaufrufe an der aktuellen Position (Zeilennummer) zurückzugeben und ein Backtrace aufzuzeichnen. Somit werden Web-Applikationen leichter zu debuggen, einfacher zu warten sein und Fehler sind allgemein besser zu reproduzieren. Die Funktionalität wurde bewusst einfach konzipiert und hilft Ihnen dabei, Skripte in einer Java ähnlichen Manier zu debuggen. Dabei liefert die parameterlose Funktion debug_backtrace() ein Array mit vier Rückgabewerten zurück, die neben den aktuellen Zeilen- und Positionsangaben noch die aufgerufenen Funktions- und Skriptnamen ausgibt (vergl. Listing 2).

Listing 2

backtrace = $backtrace;
}

function getException() {
foreach ($this->backtrace as $step) {
$msg = sprintf("%s [%s:%s]n",
$step['function'],
$step['file'],
$step['line']
);
}
return $msg;
}

function setInputFile($file) {
// ...

// if an error with this file occured
throw new XML_Parser::Exception(debug_backtrace());
}
}

try {
// ...
} catch (XML_Parser::Exception $e) {
print ($e->getException());
}
?>

Wie schon erwähnt, war die Objektorientierung in PHP4 stets ein großer Kritikpunkt, da sie in vielerlei Hinsicht Schwächen offenbarte. Elementar und oft gefordert war eine verbesserte objektorientierte Verhaltensweise und Implementierung gängiger Sprachelemente, wie man sie aus etablierten Hochsprachen wie Java oder C++ kennt. Angefangen vom Objektverhalten bis hin zum eher rudimentären Umfang unterstützter Features, wurden viele wichtige Elemente zur Vereinfachung der Programmierung oder Sprachwerkzeuge im besonderen Bezug zur OOP in der Zend Engine redlich vermisst. Oftmals wurden OO-Konzepte vom Design her sehr umständlich gelöst und boten kaum Flexibilität. Daher befinden sich die elementaren Änderungen auch mit im Objektmodell, also bei der OO-Programmierung selbst wieder. Allerdings ist PHP keine native objektorientierte Sprache, sondern bietet lediglich OO-Unterstützung an. Um eine Sprache als objektorientiert gelten zu lassen, sollten Forderungen in punkto Abstraktion, Kapselung und Vererbung erfüllt sein. Hier spricht die Schwäche der Datenkapselung als einziges Argument gegen PHP, welche nachfolgend vorgestellt wird. Die Projekte, die inzwischen mit PHP realisiert wurden und werden, sind erheblich gewachsen. Um im heutigen Businessumfeld mit komplexen Projektausrichtungen und unternehmenskritischen Applikationen bestehen zu können, ist die Objektorientierung und die Art der Ausprägung Maß aller Dinge. Sie entscheidet wesentlich über Akzeptanz oder Ablehnung einer Skriptsprache im Enterprise-Einsatz. Allerdings ist die OO-Ausprägung von PHP nicht das einzig entscheidende Kriterium, die Sprache sollte nach wie vor einfach zu erlernen sein. Insgesamt ist man sich nicht im Klaren, wo der Weg von PHP hinführen soll. Man kann sich nicht über die Art der Ausprägung einigen und hat keine klare Vision vor Augen. PHP ist die Sprache zur Generierung dynamischer Webseiten und realistisch betrachtet nicht für komplexe Software-Projekte geeignet, wo Schnelligkeit, Mächtigkeit und Integrationsfähigkeit gefragt sind. Deswegen sind Vergleiche mit Java oder anderen Hochsprachen im Zusammenhang mit OOP zum jetzigen Zeitpunkt einfach nicht relevant, da Java eine ganz andere Ausrichtung und Architektur im Gegensatz zu PHP besitzt. Diesen Entwicklungsrückstand muss PHP erst mühselig aufholen. In letzter Zeit war die Thematik und Notwendigkeit eines Application Servers eines der vorherrschenden Themen innerhalb der PHP-Entwicklung. Damit möchte PHP unmittelbar dazu beitragen, die Softwarequalität im Mittelstandssektor mit der benötigten Performanz bei komplexen Objektstrukturen zu beeinflussen. Weiterführend werden Begriffe wie Entwurfsmuster, OOA und OOD sowie UML-Case Tools, die zur konzeptionellen Planung von Software-Projekten im größeren Umfang elementar sind und in PHP5 mehr und mehr Fuß fassen, immer wichtiger. Ich möchte diese Begriffe aber nur am Rande rudimentär definieren, weil dies nicht der Schwerpunkt des Artikels ist, aber trotzdem wesentlich mit der OOP zu tun hat. Sollten Sie sich für diese Thematik ausgiebig interessieren, so kann ich nur das im 2. Quartal 2003 erscheinende Buch über die objektorientierte Programmierung für PHP Application Server von Sebastian Bergmann empfehlen, welches dieses breite Themenspektrum professionell aufgreift.

Design Patterns

Umso mächtiger die Objektorientierung einer Sprache wird, umso mehr wird die Planung objektorientierter Softwareentwicklung wichtiger und notwendiger. Entwurfsmuster (Design Patterns) [6] ebnen hier einen Weg, um wiederkehrende Entwurfsprobleme bei Softwareentwicklungsprozessen zu unterbinden und Lösungen in Form von bewährten Mustern (Patterns) bereitzustellen, um somit die Problemsituation zu erkennen und so effizient wie möglich zu lösen. Die Intention und der Grundgedanke zur Verwendung von objektorientierter Software besteht in der Widerverwendbarkeit (Code Reuse), um auch bei zukünftigen Anforderungen und Problemen zu bestehen. Der Entwurf von Software mit den zuvor genannten Ambitionen gestaltet den Prozess um einiges schwieriger. Mit der Zeit wurden Lösungen für bestimmte Probleme gefunden, die erfolgreich eingesetzt wurden und somit einen Katalog mit insgesamt 23 Entwurfsmustern pictureeten. Diese unterteilten sich jeweilig in drei Gruppen: Erzeugungsmuster, Strukturmuster und Verhaltensmuster, die typische und allseits bekannte Entwurfsmuster wie Singleton, Adapter, Iterator und Factory usw. bereitstellen.

PHP-Applikationsentwicklung mit Application Servern

In Verbindung mit komplexen Datenstrukturen in der OOP von PHP fällt immer wieder das Schlagwort Application Server. Ein Application Server stellt prinzipiell das Zusammenspiel zwischen einem Daemon (Server) und einem Programm (Application) her. In einem Application Server laufen die Applikationen persistent ab, d.h., jeder neue http-Request wird einer bereits laufenden Methode zugewiesen, die ihrerseits für ein Ergebnis sorgt. Die Vorteile sind relativ eindeutig, denn bei einer komplexen Applikation müssen nicht bei jedem neuen http-Request Objektstrukturen initialisiert werden, da nur eine Instanz für die Abarbeitung der Anfragen zuständig ist. Dies spart nicht nur Ressourcen, sondern auch wertvolle Ausführungszeit. Die von Vulcan Logic stammende Script Running Magic (SRM) [7] ist einer der Pioniere dieser Technologie innerhalb von PHP. VL-SRM bietet neben der Einführung von Applikationsvariablen in Zukunft eine Java Beans [8] ähnelnde Komponententechnologie namens Bananas, die Komponenten persistent im Speicher hält, was das Halten von komplexen Daten- und Objektstrukturen analog zum oben erwähnten Prinzip im Speicher ermöglicht. VL-SRM könnte wesentlich dazu beitragen, die Softwarequalität im Mittelstandssektor mit der benötigten Performanz innerhalb von PHP5 zu beeinflussen.

Ansprüche, Akzeptanz und Reaktionen

Beim Konzipieren von Software sollte grundlegend eine ausgiebige Planungsphase vorausgehen, die zur grundsätzlichen Zielsetzung des zu programmierenden Systems beiträgt. Diese Phase wird allgemein unter dem Begriff Objektorientierte Analyse, kurz OOA, zusammengefasst. Diese umfasst die Identifizierung aller Anforderungen in punkto: Benutzbarkeit, Effizienzsteigerung, Zuverlässigkeit, Erweiterbarkeit und Wartbarkeit. Beim objektorientierten Design (OOD) [9] bietet sich der Einsatz spezieller Entwurfswerkzeuge an, die die Kluft zwischen Design und Realisierung dadurch verkleinern, in dem man mit den Objekten der Software näher an die Realität heranrückt. Real vorkommende Prozesse oder Gegenstände werden auf wesentliche Eigenschaften reduziert und in einer Klasse zusammengefasst. Dazu trägt auch die etablierte grafische Modellierungssprache Unified Modeling Language (UML) [10] bei, welche sich als de-facto Werkzeug herauskristallisiert hat, um Geschäftsprozesse, Datenbankschemata etc. mit verschiedenen Diagrammtypen wie Use Cases, Klassen- und Interaktionsdiagrammen zu modellieren, um somit Softwaresysteme bereits vor der eigentlichen Umsetzung besser zu konstruieren und zu visualisieren. Mit der Zeit haben sich so genannte Case (Computer Acided Software Engineering)-Tools aufgetan, die den Umgang mit UML [11] erleichtern und im besten Fall den Quellcode anhand der angefertigten Diagramme selbstständig erzeugen. Ein erstes Case-Tool dieser Ausrichtung namens ArgoUML [12] glänzt bereits ansatzweise mit PHP-Unterstützung und Code Generation. Zum Glück gehören viele der oben genannten Kritikpunkte der Vergangenheit an. Nach den ersten Benchmark-Ergebnissen ergab sich ein Performanceschub von 40 bis 50 Prozent gegenüber der Zend Engine 1.0, was wohl eine deutliche Sprache spricht. Wenn man von Verbesserungen der OO-Verhaltensweise spricht, ist indirekt von der Deklarierung einer Klasse die Rede, in welcher Weise eine Instanz dieser Klasse zur Laufzeit angelegt wird und in welcher Form das Objekt nachfolgend verwendet werden kann. Gerade bei komplexen Applikationen fiel die unglaublich träge Initialisierungszeit von Objekten auf, welche Applikationen spürbar lähmte. Durch die Änderung des Java ähnelnden Referenzierungsverhaltens by reference wurde dieses Manko allerdings ausgemerzt.

Ansprüche, Akzeptanz und Reaktionen

Das Sprachverhalten der Zend Engine sah es bisher vor, beim Anlegen oder bei der Übergabe von Objektinstanzen nicht das eigentliche Objekt zu übergeben, sondern lediglich eine Kopie davon, sowie man es von Variablen (Strings, Integer etc.) kennt. Dieses Verhalten wird im Fachjargon als copy by value bezeichnet und sorgte oft für Verwirrung. Die eigentliche Kernproblematik liegt darin, dass etwaige Änderungen der Eigenschaften des Objekts sich nicht auf das Objekt selbst auswirken würden, sondern auf die Kopie des Objekts. Um wirklich nur eine Referenz auf das Objekt anzuwenden, konnte man sich nur mit der expliziten Deklarierung des &new-Operators aushelfen. Die künftige Verhaltensweise und Umgangsweise von Objekten orientiert sich strikt an OO-Sprachen wie Java. Dort wird eine Objektinstanz mit einem object handle referenziert und dieses Handle bezieht sich in allen Aktionen auf das Ursprungsobjekt. Der große Vorteil dabei ist, dass die Zend Engine 2 dies implizit erledigt, was nicht nur eleganter und flexibler ist, sondern auch bei OO-basierten Applikationen spürbar die Performance beschleunigt, allerdings auch eine Menge an Speicherressourcen beansprucht. Der konsequente Wechsel zum object by handle-Paradigma bietet aber auch Vorteile beim Umgang in punkto Usability und Semantik, wodurch Features wie Destruktoren und Dereferenzierung profitieren.

Mit der Einführung der Version 2 der Zend Engine wird eine weitere wichtige, objektorientierte Technik in den Sprachkern eingegliedert. Es handelt sich um Attribute zum Verstecken und Kapseln von Daten innerhalb von Klassen, was die Möglichkeit offenbart, die Daten nur noch den in der Klasse definierten Methoden zugänglich zu machen und den unbefugten Zugriff von außen strikt zu unterbinden. Diese Datenkapselung beschränkt sich allerdings ausschließlich auf Variablen der Klasse und nicht auf die jeweiligen Methoden. Trotz des Fehlens von Kapselung in der Zend Engine 1, konnte dieses Problem durch Konventionen und Disziplin bei der Programmierung notdürftig umgangen werden, was logischerweise alles andere als perfekt war. Die Verwendungs- und Einsatzzwecke reichen vom Verstecken private members von internen Details einer Klasse bis hin zu sichtbaren Klassenvariablen, die durch den Einsatz von privaten Attributen auf ein Minimum reduziert werden, um somit die Klassen ordentlich und elegant zu halten. Des Weiteren werden die Klassenvariablen vor einer direkten Datenmanipulierung geschützt. Somit bleibt die jeweilige Klasse stets in einem konsistenten Zustand und es entsteht eine Trennung zwischen Nutzungs- und Implementierungsebene. Aus bekannten OO-Sprachen sind einem die Schlüsselwörter private, public und protected bekannt, wobei public dafür sorgt, dass der Zugriff von Methoden oder Attributen konsequent möglich ist. Im Gegensatz zu private und protected, welche den Zugriff von außen verbieten. protected lässt nur diejenigen Attribute sichtbar erscheinen, die innerhalb der Klasse und allen weiteren Subklassen definiert wurden. private wiederum bietet eine weitere Einschränkung und ist nur innerhalb der eigenen Klasse sichtbar. Letztendlich wurde nicht nur private und protected implementiert, sondern auch public, was nichts anderes als ein Alias auf var darstellt, welches normalerweise dafür verwendet wird um Klassenattribute festzulegen.

Listing 3

method();
$obj2 =& $obj1->method();
$obj2->method();
?>

method()auf und greift darauf zu.

Listing 4

query("...");
?>

Durch die Eingliederung von statischen Klassenvariablen (static members), die durch static deklariert werden, ergibt sich zwangsläufig der Vorteil, eine Instanz einer Klasse nur einmal zu erzeugen und diese fortan kontinuierlich zu verwenden. Die meisten OO-Sprachen unterstützen dieses Konzept und bieten neben statischen Variablen auch noch statische Methoden und Klassen, was innerhalb der Zend Engine 2 nicht vorgesehen ist. Das bekannte Singleton-Design Pattern basiert unter anderem auf diesem Prinzip, welches grundlegend dafür geschaffen wurde, nur einmal zu existieren. Dies stellt auf der einen Seite eine globale Zugriffsmöglichkeit bereit und kommt dann zum Einsatz, wenn es sich um zeitintensive Objektinstanzierungen handelt.

Listing 5

counter;
print "n";
}
}

class SingletonCounter {
static $instance = NULL;

function Instance() {
if (self::$instance == NULL) {
self::$instance = new Counter();
}
return self::$instance;
}
}

SingletonCounter::Instance()->increment_and_print();
SingletonCounter::Instance()->increment_and_print();
?>

Das geänderte Zend Engine 2 Objekt-Referenzverhalten führt dazu, dass man stets eine Referenz auf eine Ursprungsklasse erzeugen kann und niemals eine Kopie eines Objekts samt Eigenschaften erhält. Wenn man komplexe Datenstrukturen besitzt und eine Klasse A erzeugt, die im weiteren Verlauf noch benötigt wird, es aber zusätzlich noch eine Klasse B gibt, die eine Kopie benötigt, um damit einzelne Teile der Objektstruktur zu bearbeiten, ohne dabei die Ursprungsinstanz der Klasse A zu verändern, spielt das neu eingeführte Klonen von Objekten (object cloning) eine bedeutsame Rolle. Dadurch erhält man sämtliche Eigenschaften des Ursprungsobjekts inklusiv aller Referenzabhängigkeiten. Ein Objekt wird nach dem Aufruf der Objektmethode __clone() geklont. Möchten Sie alle Objekteigenschaften klonen, wird zu allererst überprüft, ob Sie die Methode a __clone() selbstständig definiert haben, um das Klonen eigenmächtig zu übernehmen. In diesem Fall sind Sie dafür verantwortlich, die notwendigen Eigenschaften im erzeugten Objekt zu deklarieren. Sollte dies nicht der Fall sein, wird eine default __clone Methode aufgerufen, die alle Objekteigenschaften dupliziert. Zusätzlich wird noch eine Funktion object_clone_properties() bereitgestellt, die alle Eigenschaften des Ursprungsobjekts importiert. Somit besteht die Möglichkeit, die Eigenschaften des Ursprungsobjekts zu modifizieren, die aus irgendwelchen Gründen dringend geändert werden müssen. Ein adäquater Anwendungsfall wäre beispielsweise das Klonen von PHP-GTK Widget-Elementen. Stellen Sie sich vor, es existiert ein Objekt, welche die Ressourcen eines GTKWindow hält und darstellt. Dieses GTKWindow wird in ähnlicher Form im weiteren Programmverlauf noch einmal benötigt. Somit wird ein Duplikat oder besser formuliert eine Arbeitskopie für das weitere GTKWindow angelegt, damit einzelne Eigenschaften angepasst werden können, ohne das bestehende ursprüngliche GTKWindow Objekt zu modifizieren oder ein neues GTK-Objekt zu instanzieren.

Listing 6

connect($host, $user, $pass);
}

// Closes the connection to the MySQL server.
function disconnect() {
if (is_resource($this->connection)) {
mysql_close($this->connection);
}
}

// ...
}
?>

Das vornehmlich durch die PEAR/PECL-Entwickler geforderte Namespace/Nested Class-Konzept ist ein Versuch, die Namensraumaufteilung flexibler und sauberer zu gestalten, Komponenten in verschiedene Namespaces zu separieren und sie aus dem globalen Namespace aufzurufen. Die Projekte, die mit PHP realisiert werden, sind immer komplexer. Die Spanne reicht von einfachen Klassen bis hin zu Frameworks wie dem PEAR Repository [13]. Deswegen wird es zunehmend schwieriger, Namenskollisionen zu vermeiden. PHP4 stellte dazu exakt drei Namensräume zur Verfügung: den Globalen, Klassen- und Funktions-Namespace. Alle Namensräume inklusive der Klassennamensräume konnten Variablen enthalten. Allerdings konnte nur der globale und der Klassennamensraum Funktionen enthalten, während wiederum nur der globale Namensraum Konstanten und Klassen enthielt. Dies war eine sehr unelegante und verwirrende Lösung, um Namenskonflikten aus dem Weg zu gehen. Namespaces sind als Nested Classes implementiert, wobei damit grundlegend der Zugriff auf Attribute im Gültigkeitsbereich, welcher im Fachjargon als Scope bezeichnet wird, gemeint ist. Der Vorteil ist generell die Vermeidung von Namenskollisionen, wobei Klassen deklariert werden können, die denselben Namen aufweisen, aber einem anderen Namensraum angehören. Des Weiteren wird die modulare Zerlegung von Bibliotheken durch Bildung von Namensräumen einfacher. Namespaces wurden auf Basis des class Schlüsselworts implementiert, wobei sich der Zugriff auf Klassenattribute grundlegend unterscheidet. Fortan ist es im Gegensatz zu PHP4 möglich, innerhalb einer Klasse Konstanten, Methoden, Klassen und statische Variablen unterzubringen. Der Syntax des Zugriffsmechanismus ist folgendermaßen aufgebaut:

  • Um auf lokale Klassenattribute im Namespace zuzugreifen, verwenden Sie die Syntax self::$my_static_var bzw. MyClass::$my_static_var äquivalent.
  • Aus dem globalen Namespace werden die Funktionen explizit mit dem Schlüsselwort main:: bzw. main::function1() aufgerufen.
  • Für Konstanten, die ab sofort per const FOLDING = ‚foo‘ deklariert werden, gilt die gleiche Syntax im Stil self::MY_CONSTANT bzw. main::MY_CONSTANT aus dem globalen Namespace heraus.

Bei Methodenaufrufen innerhalb von Klassen sucht die Version 2 der Zend Engine primär im Scope der eigenen Klasse und sekundär im globalen Namespace. Sollten im Namensraum zwei gleichnamige Methoden definiert sein, kommt es auch weiterhin zu einer logischen Namenskollision. Des Weiteren existiert eine Möglichkeit, Funktionen, Konstanten und Klassen, nachfolgend Symbole genannt, aus Nested Classes heraus in den aktuellen globalen Namensraum zu importieren, welches mit dem import Statement erfolgt. Dies reduziert zusätzliche Schreibarbeit, da der gewöhnliche Klassenzugriff mittels (MyClass::) entfällt und nur einfach der Symbolname aufgeführt werden muss:

  • import * from XML::Parser; // importiert alle Symbole aus der Klasse Parser mit dem Namespace XML.
  • import function parseString, const Handler from XML::Parser // importiert einzelne Symboltypen, in diesem Fall die Funktion parseString() und die Konstante Handler.

Die Begriffe Nested Class und Namespace sind in PHP5 synonym, allerdings nicht auf syntaktischer Ebene. class MyNamespace::Classname { } deklariert eine Klasse Classname im Namespace MyNamespace und ist äquivalent zur folgenden Nested Class-Schreibweise mit einer ähnlichen Semantik:

backtrace = $backtrace;
}

function getException() {
foreach ($this->backtrace as $step) {
$msg = sprintf("%s [%s:%s]n",
$step['function'],
$step['file'],
$step['line']
);
}
return $msg;
}

function setInputFile($file) {
// ...

// if an error with this file occured
throw new XML_Parser::Exception(debug_backtrace());
}
}

try {
// ...
} catch (XML_Parser::Exception $e) {
print ($e->getException());
}
?>

Die nicht unmittelbar mit der Zend Engine 2 eingeführten und als sehr experimentell zu bezeichnenden Features pictureen eine weitere Etappe auf dem Weg zu PHP5 mit erweiterten OO-Möglichkeiten. Innerhalb von PHP4 stellte man oftmals die Notwendigkeit fest, Klassen zu erweitern oder anzupassen. Das im OO-Fachjargon auch als Vererbung bezeichnete Prinzip sah es vor, eine Reihe von existierenden Strukturen aus bereits alten Objekten zu übernehmen, um somit gleichartige oder ähnelnde Methoden respektive Attribute nicht neu zu implementieren. Beim ursprünglichen Objekt, von dem geerbt wurde, spricht man nun von einer Basis- oder Superklasse. Eine aus der Sprache C++ bekannte Methode erlaubt es, dass eine abgeleitete oder geerbte Klasse mehrere Basisklassen besitzen kann. Dabei handelt es sich um die Möglichkeit, parallel, also gleichzeitig, von zwei Klasseneigenschaften zu erben. In diesem Kontext wird dann oftmals von Mehrfachvererbung (multiple inheritance) gesprochen. Dieses Prinzip war ein lang diskutierter Themenpunkt, wobei die Performance Nachteile bei einer möglichen aufwändigen Implementierung letztendlich überwogen. Die Essenz dieser Diskussion stellte sich als durchaus positiv heraus, da man auf dem Grundprinzip zum gleichzeitigen Erben von Eigenschaften aus zwei verschiedenen Objekten weiterhin beharrte. Eine allgemeine akzeptierte Lösung pictureete die Aggregations-Methode, die ebenfalls eine Mehrfachvererbung von Klassen durch Zusammenführen der Eigenschaften und Methoden zur Laufzeit ermöglicht. An ein Beispiel zur Veranschaulichung der erwähnten Theorie möchte ich an dieser Stelle verzichten und auf den Dev.Talk [14] von Sebastian Bergmann im PHP Magazin 2/2002 verweisen. Bei einer weiteren Extension, die noch vor dem Release der Zend Engine 2 veröffentlicht wurde, handelt es sich um das Overloading. Hierbei ist das benutzerdefinierte Überladen der Zugriffe auf Klassenvariablen und Methodenaufrufe möglich, wodurch allgemein die Existenz von Methoden gleichen Namens möglich ist, sofern sie sich in der Art oder Anzahl ihrer Parameter unterscheiden. Die Overloading-Extension besitzt lediglich eine Funktion overload(), welche den Namen der Klasse benötigt, um das Überladen von Eigenschaften und Methoden für eine Klasse zu aktivieren. Um das Überladen zu ermöglichen, müssen allerdings entsprechende Methoden: __get(), __set() und __call() innerhalb des Objekts deklariert werden. Ein beiläufiges Beispiel finden Sie ebenfalls unter [14]. Des Weiteren wurde zum gegenwärtigen Zeitpunkt noch über eine Alternative zur Mehrfachvererbung nachgedacht, wobei es sich um die aus Java stammenden Delegationen handelte, die dem PHP Paradigma sehr entgegen kommen.

backtrace = $backtrace;
}

function getException() {
foreach ($this->backtrace as $step) {
$msg = sprintf("%s [%s:%s]n",
$step['function'],
$step['file'],
$step['line']
);
}
return $msg;
}

function setInputFile($file) {
// ...

// if an error with this file occured
throw new XML_Parser::Exception(debug_backtrace());
}
}

try {
// ...
} catch (XML_Parser::Exception $e) {
print ($e->getException());
}
?>

PHP5 respektive die Version 2 der Zend Engine pictureet einen großen Sprung zu einer mächtigeren dynamischen Skriptsprache unter Beibehaltung einer PHP-üblichen einfachen Syntax. Gängige OO-Konzepte können über PHP5 geplant, entworfen und umgesetzt werden. Der Einsatz von PHPDoc als Dokumentationstool wird zunehmend wichtiger werden, um den Überblick über seine APIs beizubehalten. Einige der ursprünglichen Doc Comments mit OO-Hintergrund finden jetzt endlich einen probaten Anwendungszweck. @static deklariert statische Membervariablen, @throws informiert den Aufrufer über einen möglichen Fehler zur Laufzeit des Programms, welcher mit Hilfe des Exception Handlings diagnostiziert wurde. @access dient zum Kennzeichnen von private, public oder protected Attributen zur Datenkapselung der Objekte. Weitere Informationen zur Verwendung von Doc Comments finden Sie unter [15]. Des Weiteren werden Klassen schon im Voraus in verschiedenen Testbedingungen auf Basis von Unit-Tests (PHP Unit) mehr und mehr getestet und ausprogrammiert werden, bevor mit der eigentlichen Programmierung begonnen wird, um die Softwarequalität zu steigern. Beim Schreiben des Artikels stand die Veröffentlichung der dritten Alpha-Version [16] der Zend Engine 2 kurz bevor, die knapp ein Jahr nach Entwicklungsbeginn veröffentlicht wurde. Diese basiert auf dem aktuellen PHP4 CVS (4.3.0-dev). Da die Zend Engine 2 sich immer noch nicht für den Einsatz in Produktionsumgebungen eignet, können Sie in jedem Fall beim Testen mithelfen, um Fehler oder Ungereimtheiten aufzuspüren und somit eine schnellere Veröffentlichung von PHP5 zu gewährleisten. Scheuen Sie sich des Weiteren nicht davor, Meinungen oder vermisste Features ihrerseits der Zend Engine 2 Mailingliste mitzuteilen, die generell dafür geschaffen wurde, um Lösungen zu Problemen zu finden und als zentrale Diskussionsstätte zu fungieren. Möchten Sie die aktuelle, unstabile CVS-Version testen, so laden Sie sich aus dem CVS zuerst den PHP-Quellcode herunter, wonach Sie sich im Zend-CVS das Verzeichnis Zend Engine2 herunterladen. Als letztes benennen Sie das Verzeichnis in Zend um und kompilieren PHP neu. Oftmals wird nach der Veröffentlichung von PHP5 respektive Zend Engine 2 gefragt. Dies ist sicherlich eine gute Frage, worauf selbst die Entwickler zum gegenwärtigen Zeitpunkt keine genaue Antwort wissen. Die Veröffentlichung von PHP5 hängt im besonderen Maße von der Fertigstellung der Zend Engine 2 ab, die sich noch vor einer langwierigen und intensiven Testphase befindet. Aber realistisch betrachtet könnte man mit der Veröffentlichung Ende 2002 rechnen. Kritisch betrachtet weisen allerdings viele Leistungsmerkmale eklatante Designschwächen auf. Neben einer unzulänglich implementierten Datenkapselung, wobei auf private Klassenmethoden verzichtet wurde, existieren vielerlei weitere konzeptionelle Schwächen. PHP5 respektive die Version 2 der Zend Engine besitzt vielerlei Möglichkeiten und Potenziale, wobei schätzungsweise ein Entwicklungsrückstand von rund fünf bis sechs Jahren in Design- und Konzept-Aspekten im Vergleich zu anderen Sprachen aufzuholen ist, allerdings steht die Konkurrenz nicht still und entwickelt sich auch stetig weiter. PHP5 hat sich in punkto Objektorientierung zwar weiterentwickelt, aber die Lösungen (gerade Kapselung) entsprechen nicht einem wohlüberlegtem Konzept und spiegeln die Einstellung der Kernentwickler sehr gut wieder. Es muss endlich eine andere Philosophie und Denkweise bei den Kernentwicklern einkehren. Dass Software funktioniert, ist eine Grundvoraussetzung, aber um die angesprochenen Segmente bzw. Ziele zu erreichen, ist eine gute Softwarearchitektur notwendig. Deswegen muss man sich davon distanzieren, PHP einfach nur so weiter zu entwickeln, dass es ordnungsgemäß funktioniert, sondern endlich über wohlüberlegte Konzepte nachdenken, die zwar einen längeren Entwicklungszyklus beanspruchen, aber wesentlich die langfristige Qualität und die Akzeptanz von PHP verbessern. Vielleicht hätte man sich für die Entwicklung der Zend Engine 2 noch mehr Zeit nehmen sollen, um wirklich alle Features perfekt ausgefeilt zu veröffentlichen und die Engine nicht in Rekordzeit zu entwickeln. Aber bei allem sollten wir nicht vergessen, dass PHP auf Open Source basiert. Open Source lebt bekanntlicherweise von der freiwilligen Bereitschaft der Entwickler, welche sehr hoch anzurechnen ist. Aber nicht nur die Sprache ist zu kritisieren, auch die träge Entwicklung von Third Party-Produkten, die von Firmen endlich nachgereicht werden müssen. Damit sind gute IDEs, Profiler/Debugger, effiziente Dokumentationstools, Test- und Komponentenframeworks wie SRM gemeint. In dieser Richtung hat sich in letzter Zeit zwar etwas getan, aber man kann gespannt sein, was die Zukunft mit sich bringt. Andre Gildemeister (ag@inocreation.com) ist Geschäftsführer von inocreation. Dieses Unternehmen (www.inocreation.com/) befasst sich verstärkt mit der Software-Entwicklung im web-basierten Umfeld und dessen Technologien. Des Weiteren ist er als freier Autor für verschiedene Online- und Print-Magazine rund um PHP und Webtechnologien tätig.

  • [6] „Design Patterns“, Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Addison Wesley, Englische Ausgabe, ISBN 0201633612
  • [9] „Objektorientierte Softwareentwicklung“, Bernd Oestereich, Oldenbourg Wiss., Deutsche Ausgabe, ISBN 3486255738
  • [11] „UML konzentriert. Strukturierte Einführung in die Standard-Objektmodellierungssprache“, M.Fowler, K.Scott, Addison Wesley, Deutsche Ausgabe, ISBN 3827316170
  • [14] Sebastian Bergmann: „Dev.Talk: Persistente Objekte – Aggregation und Overloading“, PHP Magazin 2.02
  • [15] Andre Gildemeister: „Effiziente Dokumentation: API Dokumentationen mit PHPDoc generieren“, PHP Magazin 1.02
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -