136 31 9MB
German Pages 487 Year 2005
Sandini Bib
PHP
Sandini Bib
Sandini Bib
MASTER CLASS
Andreas Barchfeld
PHP
Einstieg für Anspruchsvolle
ADDISON-WESLEY
[ in Kooperation mit ]
Sandini Bib
Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar. Die Informationen in diesem Buch werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Produkt wurde auf chlorfrei gebleichtem Papier gedruckt.
10 9 8 7 6 5 4 3 2 1 08 07 06 05
ISBN 3-8273-2181-6
© 2005 Pearson Studium, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten www.pearson-studium.de Lektorat: Frank Eller, [email protected] Einbandgestaltung: Marco Lindenbeck, webwo GmbH ([email protected]) Herstellung: Elisabeth Prümm, [email protected] Satz: mediaService, Siegen (www.media-service.tv) Druck und Verarbeitung: Kösel, Krugzell (www.KoeselBuch.de) Printed in Germany
Sandini Bib
Inhaltsverzeichnis Vorwort Kapitel 1 Installation und Konfiguration 1.1 XAMPP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Binärinstallation für den IIS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.1 PHP. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2.2 IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Binärinstallation Apache/PHP unter Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.1 Installation des Apache-Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.2 Konfiguration des Apache-Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3.3 Apache auf der Befehlszeile (auch als Dienst) . . . . . . . . . . . . . . . . . . . . . . . 1.4 Installation aus den Quellcode-Dateien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.1 Apache-Installation unter Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.2 PHP-Installation unter Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.4.3 PHP-Installation unter Windows. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5 PEAR-Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5.1 Installation per Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.5.2 Kommandozeilen-Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Kapitel 2 Erste Schritte 2.1 Was ist PHP? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Ein Überblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Programmaufruf. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Aufbau eines Skripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Kapitel 3 Variablen und ihre Datentypen 3.1 3.2 3.3 3.4 3.5 3.6
11 15 15 17 17 20 23 23 28 37 41 42 45 49 57 58 63
67 68 68 70 76
97
Überblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Was ist eine Variable? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Variablennamen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Variable Variablennamen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Vordefinierte Variablen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 Konstante Werte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
5
Sandini Bib Inhaltsverzeichnis
3.7 3.8 3.9 3.10 3.11
3.12 3.13 3.14
3.15 3.16 3.17 3.18 3.19 3.20
3.21
6
Variablendeklaration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PHP-Datentypen – eine Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Der logische Datentyp BOOLEAN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Logische Operatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Vergleichsoperatoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.11.1 Die Operatoren > und >= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.11.2 Die Operatoren < und
372
Sandini Bib Statik
In der Methode getHandle() steckt die Logik für die Benutzung nur einer Klasse. Sollte die Variable $handle noch keinen Wert haben, wird ein neues Objekt der Klasse PatientNumberCreator erstellt und dieser Variablen zugeordnet. Dabei wird dann auch ein Pool an Nummern erzeugt bzw. von der Datenbank geladen. Dieses neue Objekt ($handle) wird dann an den Aufrufer zurückgegeben. Sollte ein solches handle schon existieren, wird kein neues Objekt erzeugt! Fatal error: Call to private PatientNumberCreator::__construct() from context '' in C:\PROJEKTE\PHPBUCH\06\Code\singleton.php on line 41
Listing 7.10 Versuch, eine Instanz von PatientNumberCreator zu erstellen
Am Ende des Skripts wird die Klasse zweimal aufgerufen. Wie Sie an der Ausgabe in Listing 7.11 erkennen, wird das Handle nur beim ersten Aufruf generiert. Neue Nummer: (neues Handle) 8 Neue Nummer: 4
Listing 7.11 Ausgabe des Skripts aus Listing 7.9
Übrigens: Sie haben soeben Ihr erstes Muster kennen gelernt: das Singleton. Das Singleton-Muster zeichnet sich dadurch aus, dass ein Objekt dieses Musters im Programmverlauf nur einmal existieren kann.
7.2.5 Objekte kopieren Wenn Sie ein Objekt einer Klasse erstellt haben, können Sie dieses Objekt ohne weiteres „kopieren“. Dies geht über die Zuweisung $object1 = object2;
Wenn man sich diese harmlose Zeile anschaut, sieht man nicht sofort, dass dort eine Fehlerquelle versteckt ist, wenn man nicht aufpasst. Schauen Sie sich dazu die Klasse Person in Listing 7.12 einmal an. Es handelt sich um eine stark verkürzte Fassung dieser Klasse. An dieser Stelle soll nur einmal der Vorname interessieren. Wenn Sie nun zwei Personen haben, bei denen bis auf den Vornamen und das Geburtsdatum alle weiteren Daten übereinstimmen, kommt man leicht in die Versuchung, dieses Objekt zu kopieren und die geänderten Daten über die entsprechenden set…-Methoden neu zu setzen. Daran ist an sich nichts Falsches, aber schauen Sie sich im weiteren Verlauf von Listing 7.12 das Verhalten der Objekte einmal an.
373
Sandini Bib 7 Objektorientierte Programmierung
Es wird ein Objekt $mother aus der Klasse Person erstellt, wobei der Vorname bei der Erstellung mit übergeben wird. Dieser Wert wird über die getChrName()-Methode direkt wieder ausgegeben. Dieses Objekt $mother wird nun als Objekt $child kopiert. Das neue Objekt $child bekommt einen neuen Vornamen zugewiesen. Auch dieser Wert wird zur Kontrolle direkt wieder ausgegeben. In Listing 7.13 können Sie die Protokollausgaben dieses Skripts verfolgen. Listing 7.12 Objekt kopieren, ohne Vorbereitung der Klasse
So weit scheint alles gut verlaufen zu sein. Beide Objekte existieren, und alle Attribute haben einen Wert. Wenn Sie jetzt aber den Vornamen der Mutter nochmals ausgeben, sehen Sie etwas Erstaunliches. Die Mutter
374
Sandini Bib Statik
hat den Vornamen des Kindes bekommen! Wenn Sie schon einmal mit PHP 4 in dieser Hinsicht gearbeitet haben, werden Sie erst recht erstaunt sein. In PHP 4 hätte die Mutter noch ihren eigenen Vornamen. Vorname der Mutter: Ute Vorname des Kindes: Ingo
Listing 7.13 Veränderung der Daten im Verlauf des Skripts aus Listing 7.12
aber: Vorname der Mutter: Ingo
In PHP 5 wurde die gesamte Objektorientierung neu gestaltet! Dies hat nicht nur zur Folge, dass PHP 5 jetzt wirklich objektorientiert ist, sondern hat trotz aller Abwärtskompatibilität einige Änderungen zur Folge. Während in PHP 4 bei einer Kopie wie in Listing 7.12 alle Daten wirklich dupliziert wurden, wird bei einer solchen Kopie in PHP 5 nur eine Referenz auf das ursprüngliche Objekt gesetzt. Das Objekt links vom Gleichheitszeichen ist also nur eine Referenz auf das Objekt der rechten Seite. Damit schlagen alle Änderungen des neuen Objektes natürlich auf das Ursprungsobjekt durch. Daher hat das Objekt $mother in Listing 7.12 auch den Vornamen des Objektes $child bekommen. Wenn Sie das Skript so abändern, wie es in Listing 7.14 aufgeführt ist, werden alle Daten in das neue Objekt dupliziert. Das neue Objekt ist ein Klon des alten. // clone objects $mother = new Person( "Ute" );
Listing 7.14 Klonen von Objekten
$child2 = clone $mother; $child2->setChrName( "Andreas" ); echo "\n\njetzt:"; echo "\nVorname des Kindes: " . $child2->getChrName(); echo "\nVorname der Mutter: " . $mother->getChrName();
Wenn Sie sich die Ausgabe dieses Skripts ansehen, sind alle Daten der Objekte richtig. Das liegt aber auch daran, dass Sie nach dem Klonen des Ursprungsobjektes $mother dem neuen Objekt $child direkt einen neuen Wert für den Vornamen gegeben haben. Man kann sich aber auch Daten oder Objekte vorstellen, wo dies so schnell nicht möglich ist. Denken Sie in diesem Fall beispielsweise an die Versicherungsnummer. Das Kind wird nach der Geburt nicht sofort eine Versicherungsnummer haben. Dies wird einige Tage dauern. Woran erkennen Sie nun, welche Personendaten noch verändert werden müssen?
375
Sandini Bib 7 Objektorientierte Programmierung
Listing 7.15 Richtige Daten durch Klonen der Objekte (Listing 7.14)
jetzt: Vorname des Kindes: Andreas Vorname der Mutter: Ute
Es wäre also von Vorteil, beim Klonen eines Objektes an den relevanten Stellen automatisch Default-Werte zu hinterlegen. Auch daran wurde gedacht. Sie müssen in der Klasse eine Methode mit dem Namen __clone() bereitstellen. In dieser Methode können Sie beim Klonen eines Objektes dieser Klasse auf den Kopiervorgang Einfluss nehmen. In Listing 7.16 sehen Sie die Klasse Person um diese Methode erweitert. In dieser Methode wird geprüft, ob das Attribut $_chrName einen Inhalt hat. Ist dies der Fall, wird der dort gespeicherte Wert nicht übernommen, sondern durch einen anderen ersetzt, in diesem Beispiel durch die Zeichenkette "***FEHLT***". Listing 7.16 Manipulation des Kopiervorganges durch __clone()
Die Ausgabe des Skriptes finden Sie im folgenden Listing 7.17. Wie Sie sehen, wird beim Klonen des Objektes der Wert des Ursprungsobjektes überschrieben. Nach dem Klonen Vorname der Mutter: Ute Vorname des Kindes: ***FEHLT***
Listing 7.17 Ausgabe für die modifizierte Klasse mit der Methode __clone()
Nach setChrName() Vorname der Mutter: Ute Vorname des Kindes: Ingo
Dies ist ein Beispiel für den Einsatzbereich dieser Methode. Wenn Sie Objekte von Ressourcen haben (Dateizeiger oder Datenbankverbindungen), können Sie die Methode __clone() beispielsweise auch dafür einsetzen, diese Ressourcen für das neue Objekt zurückzusetzen.
7.2.6 Polymorphismus von Klassen Mit dem Begriff Polymorph werden Dinge bezeichnet, die verschiedene Gestalten annehmen können. Polymorphismus zählt zu einer der wichtigen Eigenschaften objektorientierter Programmiersprachen. So kann diese Eigenschaft natürlich in PHP nicht fehlen. In der objektorientierten Programmierung versteht man unter Polymorphismus die Fähigkeit einer Klasse, eines Objektes oder einer Funktion nach außen hin immer gleich zu erscheinen, sich intern jedoch, je nach Objekt, anders zu verhalten Was im ersten Augenblick nach einer komplizierten Arbeitsweise klingt, ist in der Praxis meist nicht so kompliziert Schauen wir uns dazu das Beispiel aus Listing 7.18. Es werden drei Klassen definiert, von denen eine Klasse (Person) nur dazu dient, als Vorlage für abgeleitete Klassen (Worker und Manager) zu dienen. Diese beiden Klassen übernehmen bis auf eine Ausnahme alle Attribute und Methoden der Elternklasse Person. Diese eine Ausnahme ist die Methode getSalary(). Sie wird in den beiden abgeleiteten Klassen neu definiert. Je
377
Sandini Bib 7 Objektorientierte Programmierung
nach Klasse wird ein Bonus zugerechnet, der in der abgeleiteten Klasse definiert wird. Bis zu diesem Punkt gibt es noch keine gravierenden Neuigkeiten. Diese stecken in der Funktion printSalaryStatement(). Der Funktion wird ein Objekt, hier $employee, übergeben. Innerhalb der Funktion wird getestet, ob es sich bei dem Objekt um eine Instanz der Klasse Person handelt. Sollte dies der Fall sein, wird die Methode getSalary() aufgerufen. Nach diesen Vorarbeiten werden zwei Objekte der Klassen Worker und erzeugt. Dabei wird beiden Klassen das identische Grundgehalt übergeben. Anschließend werden beide Objekte in ein Array gepackt. In der Realität hätte man es hier mit einer Liste von wesentlich mehr Angestellten zu tun. Manager
Diese Liste wird nun über eine foreach-Schleife ausgegeben. Innerhalb der Schleife wird für das jeweils aktuelle Objekt die Funktion printSalaryStatement() aufgerufen. Listing 7.18 Polymorphismus am Beispiel einer Gehaltsabrechnung
Im ersten Durchlauf der Schleife handelt es sich um das Objekt $emp_mangr. Dieses Objekt wird also an die Funktion printSalaryStatement() übergeben. Da dieses Objekt eine Instanz der Klasse Person ist, wird die Methode getSalary() aufgerufen. Da es sich um das ManagerObjekt handelt, wird dessen Methode genutzt. Im zweiten Durchlauf wird das Objekt $emp_work übergeben. Folglich wird die getSalary()-Methode dieses Objektes zur Ausgabe genutzt. Die Ausgabe dieses Skripts finden Sie in Listing 7.19. Sie sehen, jeder bekommt das richtige Gehalt.
379
Sandini Bib 7 Objektorientierte Programmierung
Listing 7.19 Ausgabe der Gehaltsliste
2500 1200
In der klassischen, funktionsorientierten Programmierung hätten Sie hier eine längere if- oder switch-Anweisung stehen. Und jedes Mal, wenn eine neue Variante dazukam (z. B. der Hilfsmanager), mussten Sie so gut wie alles neu anpacken und erweitern. In der objektorientierten Programmierung benötigen Sie nur eine neue, von Person abgeleitete Klasse. Die Funktion printSalaryStatement() und die Ablaufslogik für die Zahlungsliste muss nicht verändert werden! Sie bleibt gleich, egal wie viele abgeleitete Klassen Sie noch implementieren.
7.2.7 Type Hint Im Listing 7.18 haben wir mit dem Typ-Operator isinstanceof getestet, ob eine Klasse eine abgeleitete Klasse von Person ist. Mit PHP 5 gibt es die Möglichkeit, bei der Übergabe an Funktionen und Methoden, dem PHP-Interpreter einen Hinweis zu geben, welche Klasse übergeben werden darf (daher auch der Name Type Hint). In Listing 7.20 sehen Sie die Funktion printSalaryStatement() mit einem solchen Typ-Hinweis. Sollte diese Funktion mit einer Variablen aufgerufen werden, die nicht direkt oder indirekt von der Klasse Person stammt, wird ein Fehler ausgegeben. Listing 7.20 Verbesserte Form der Funktion printSalaryStatement() mit Type Hint
function printSalaryStatement( Person $employee ) { echo $employee->getSalary(); echo "\n"; }
7.2.8 Abstrakte Klassen In Listing 7.18 haben wir die Klasse Person nur so weit bearbeitet, dass damit weitere Klassen davon abgeleitet werden konnten. Da es sich aber um eine normale Klasse handelt, kann man auch von dieser Klasse Person ein Objekt erstellen. Manchmal ist dieses Verhalten nicht gewünscht. Man möchte eine Klasse erstellen, von der man zwar ableiten kann, von der aber auf keinen Fall eigene Objekte erstellt werden dürfen. Um dies zu gewährleisten, gibt es in der objektorientierten Programmierung das Prinzip der abstrakten Klasse. In PHP wird eine Klasse mit dem Schlüsselwort abstract eingeleitet. Die Klasse Person aus Listing 7.18 wird so zu der in Listing 7.21 dargestellten Klasse.
380
Sandini Bib Statik
abstract class Person { protected $_salary;
Listing 7.21 Die Klasse Person als abstrakte Klasse
public function __construct( $salary ) { $this->_salary = $salary; } public function getSalary() { return $this->_salary; } public function setSalary( $salary ) { $this->_salary = $salary; } }
Wenn Sie jetzt versuchen, mit $emp_pers = new Person( 1000.0 );
ein Objekt dieser Klasse zu erstellen, bekommen Sie die Fehlermeldung aus Listing 7.22.
Fatal error: Cannot instantiate abstract class Person in C:\Code\poly3.php on line 50
Listing 7.22 Fehlermeldung bei der Instanziierung einer abstrakten Klasse
Auf diese Weise sind Sie und jeder andere Programmierer, der mit dieser Klasse arbeiten möchte, gezwungen, eine neue Klasse hiervon abzuleiten. Dabei kann man aber vielleicht vergessen, eine klasseneigene Methode für getSalary() zu schreiben. Dann verwendet die neue Klasse automatisch die Methode der Elternklasse. Um auch dies zu verhindern, können Sie diese Methode in der Klasse Person als abstrakt definieren. Dafür darf die Methode keinen Funktionskörper mehr haben. Sie besteht nur nach aus der Kopfzeile der Methode. In Listing 7.23 finden Sie die Definition der abstrakten Klasse Person mit der abstrakten Methode getSalary(). abstract class Person { protected $_salary;
Listing 7.23 Definition der abstrakten Funktion getSalary()
public function __construct( $salary ) { $this->_salary = $salary; } abstract public function getSalary();
381
Sandini Bib 7 Objektorientierte Programmierung
public function setSalary( $salary ) { $this->_salary = $salary; }
Listing 7.23 (Forts.) Definition der abstrakten Funktion getSalary()
}
Wenn Sie eine Klasse haben, die keine Attribute und nur abstrakte Klassen besitzt, so können Sie diese Klasse weiterhin als abstrakte Klasse weiterlaufen lassen. Eigentlich haben Sie es dabei aber mit einem so genannten interface zu tun. In Listing 7.24 ist Person als Interface realisiert. Sie besteht nur noch aus den beiden abstrakten Methoden getSalary() und setSalary(). Listing 7.24 Definition eines Interface
382
Sandini Bib Statik
Wenn Sie von einem Interface eine neue Klasse ableiten, müssen Sie alle Methoden in der abgeleiteten Klasse mit Leben füllen. Sie benutzen auch nicht mehr das Schlüsselwort extends, sondern implementieren diese Klasse ja eigentlich vollkommen neu. Daher wird das Schlüsselwort implements verwendet. Während Sie immer nur von einer Klasse erben können, sind Ihnen bei den Interfaces beliebig viele Vererbungen erlaubt. Auf diese Art können Sie in PHP so etwas wie Mehrfachvererbung realisieren.
7.2.9 Assoziationen In der Praxis findet man häufig den Fall, dass eine Klasse als Attribut eine weitere Klasse beinhaltet. Eine Person hat eine Adresse und ist nicht eine Erweiterung einer Adresse (siehe auch 7.3). In einem solchen Fall spricht man auch von einer Klassenassoziation. In Listing 7.25 finden Sie zwei Klassen, Address und Person. In der Klasse Address sind der Übersichtlichkeit halber nur der Konstruktor und die Methode getEMail() implementiert. In der Klasse Person sind auch nur einige der notwendigen Methoden realisiert. Im Konstruktor der Klasse werden die Daten der Person übergeben. Unter anderem werden auch die Adressdaten als Parameter im Konstruktor aufgeführt. Im Konstruktor wird ein neues Objekt der Klasse Adress erstellt. Da die Klasse Person aber keine von Adress abgeleitete Klasse ist, kann man so ohne weiteres nicht auf die Daten dieser Klasse zugreifen. Für jedes Attribut der Klasse Adress muss man eine eigene Methode schreiben, die auf die entsprechende Methode der Klasse Adress zugreift. In der Methode getEMail() der Personenklasse holt man sich über $this>_Adress das Klassenattribut für die Adresse. Da es sich hierbei um ein Objekt handelt, kann man direkt auf die Methode getEMail() des Adress-Objektes zugreifen. Insgesamt ergibt sich damit der Zugriffspfad $this->_Adress->getEMail(). In Summe kann dies sehr schreibintensiv sein.
384
Sandini Bib Statik
Als Test wird ein Objekt der Klasse Person erzeugt, und die beiden Übergabeparameter werden über die get...-Methoden direkt wieder ausgegeben. Wenn Sie dieses Skript laufen lassen, erhalten Sie die Ausgabe Andreas hat die eMail-Adresse: [email protected]
PHP 5 bietet Ihnen mit der Funktion __call() eine elegante Möglichkeit, den Aufruf der Adress-Methoden zu verkürzen. Normalerweise bekommen Sie eine Fehlermeldung, wenn Sie eine Klassenmethode aufrufen, die es nicht gibt. Mit __call() können Sie darauf Einfluss nehmen. Wenn eine Klasse diese spezielle Methode implementiert, wird bei einer unbekannten Methode diese Methode aufgerufen. Dieser Methode werden von PHP im ersten Parameter der Name der aufgerufenen Methode und im zweiten Parameter die Übergabeparameter dieser unbekannten Methode übergeben. Jetzt müssen Sie nur noch nachschauen, ob es eine Methode dieses Namens in dem Adress-Objekt gibt. Wenn dies der Fall ist, können Sie die Methode der Klasse aufrufen. Da Sie nur den Namen der Methode haben, müssen Sie diesen in eine richtige Methode umwandeln (für C/C++-Programmierer: Callback über Funktionszeiger). Seit PHP 4.0.4 existiert für solche Zwecke die Funktion call_user_func_array(). Dieser Funktion werden im ersten Parameter der Funktionsname und im zweiten die entsprechenden Werte für diese Funktion übergeben. call_user_func_array() ruft dann die Funktion mit diesem Namen auf. Bei Objekten müssen Sie an die erste Stelle ein Array setzen, welches das Objekt und die aufzurufende Methode enthält. All dies zusammengesetzt führt zu der in Listing 7.26 gezeigten Methode __call. public function __call( $method, $attribut ) { if ( method_exists( $this->_Adress, $method ) ) {
Listing 7.26 Die Methode __call der Klasse Person zum Aufruf der Adress-Methoden
$func = array( $this->_Adress, $method ); $func_arr = call_user_func_array( $func, $attribut ); return $func_arr; } else { return false; } }
385
Sandini Bib 7 Objektorientierte Programmierung
Wenn Sie diese Methode in die Klasse Person einsetzen, brauchen Sie nicht für jede Methode der Klasse Adress ein Gegenstück in Person zu integrieren. Dies erledigt jetzt die Methode __call(). Und Sie haben noch einen weiteren Vorteil durch diese Vorgehensweise: Wenn Sie in der Klasse Adress neue Methoden einführen, haben Sie diese in der Klasse Person automatisch integriert. Klassenassoziationen werden noch in „Aggregation“ und „Komposition“ aufgeteilt. Bei dem gerade besprochenen Beispiel handelt es sich um eine Komposition. Wenn ein Objekt der Klasse Person im laufenden Programm gelöscht wird (z.B. über unset()), so wird auch die dazugehörige Adresse gelöscht. Etwas anders liegt der Fall, wenn Sie ein Objekt außerhalb einer Klasse erstellen und dieses fertige Objekt dann einem Attribut einer anderen Klasse zuordnen. Beispielsweise könnte es ein Attribut „Ehegatte“ in der Klasse Person geben. Dieses Attribut ist ebenfalls eine Person. Wenn Sie dann die Objekte $man und $women erstellen, können Sie eine Zuweisung $women->Ehegatte = $man treffen. Löschen Sie dann irgendwann das Objekt $woman wieder, bleibt das Objekt $man bestehen. Bei einer solchen Konstellation spricht man von Aggregation.
7.3
Zusammenspiel der Objekte
Die beiden Klassen aus Abbildung 7.1 zeigen ein paar Möglichkeiten der objektorientierten Programmierung. Nun besteht ein Programm nicht nur aus Vererbung von Klassen. Die objektorientierte Sichtweise bietet noch ein paar mehr Möglichkeiten, Klassen miteinander zu verbinden. Im Folgenden betrachten wir eine sehr stark vereinfachte Form eines Krankenhaus-Informationssystems, kurz KIS. In diesem KIS werden Patienten verwaltet. Die Speicherung der Daten in einer Datenbank ist an dieser Stelle nicht aufgeführt. Das Beispiel soll Ihnen die objektorientierte Sichtweise von PHP etwas näher bringen. Zusätzlich sind einige Themen eingeflossen, die direkt mit der Objektorientierung nichts zu tun haben. Die für das Programm relevanten Teile werden erläutert. Sie sollen auch einen kleinen Überblick geben, was es an Tools und Möglichkeiten gibt, die einem bei größeren Programmen die Arbeit erleichtern können.
386
Sandini Bib Zusammenspiel der Objekte
7.3.1 Aufbau des Informationssystem Der Aufbau unseres Mini-KIS lässt sich mit ein paar Worten beschreiben: Eine Person, in diesem Zusammenhang auch als Patient bezeichnet, hat keinen, einen oder mehrere Aufenthalte im Krankenhaus. Da die Anzahl zu Beginn der ersten Behandlung nicht feststeht, kann man keine feste Zuordnung treffen. In solchen Situationen behilft man sich mit einer so genannten Container-Klasse. Eine solche Klasse dient genau diesem Zweck: eine unbestimmte Anzahl von Objekten einer Klasse aufzunehmen. Jede Person hat also Null oder einen Container für die Aufenthalte. Wenn es einen Container gibt, gehört dieser zu einer Person. In einem Aufenthaltscontainer befinden sich null bis beliebig viele Aufenthalte einer Person. Diese 0-zu-n-Relation wird nicht über einen Container realisiert. Zu jedem Aufenthalt gehört mindestens eine Diagnose. Es können aber auch beliebig viele Diagnosen gestellt werden. Dieser Zusammenhang wird ebenfalls nicht über einen Container realisiert. Als Letztes gehört zu jedem Aufenthalt mindestens eine Abrechnung. Dauert der Aufenthalt sehr lange, können mehrere Abrechnungen auftreten. Die grafische Umsetzung dieser Beziehungen und die Attribute und Methoden der jeweiligen Klassen finden Sie in Abbildung 7.2 als UMLDiagramm. Bei der Verbindung zwischen den Klassen „Person“ und „AufenthaltContainer“ sowie zwischen „Abrechnung“ und „Aufenthalt“ handelt es sich um so genannte Assoziationen. Bei den Verbindungen mit der angehängten Raute spricht man von Aggregation. Immer wenn es um Objekte geht, die sich aus Teilen zusammensetzen, kann man an Aggregation denken. Es gibt noch eine verstärkte Form der Aggregation, die Komposition. Diese wird in diesem Beispiel nicht verwendet. Die Komposition wird mit einer ausgefüllten Raute dargestellt.
UML = Unified Modelling Language, zurzeit in der Version 2.0
387
Sandini Bib 7 Objektorientierte Programmierung
Abbildung 7.2 Aufbau des KIS
In der Abbildung 7.2 ist bei den einzelnen Methoden an einigen Stellen die Anmerkung und zu finden. Mit dieser Typisierung wird angezeigt, dass es sich bei den jeweiligen Methoden um solche handelt, mit denen Attribute gesetzt oder gelesen werden können. Die Umsetzung dieser Abbildung in die einzelnen Klassen finden Sie in den nächsten Kapiteln.
7.3.2 Die Klasse Person In der Klasse Person aus Listing 7.28 fallen zuerst die ungewöhnlichen Kommentare auf. Diese gehören zwar nicht direkt zur objektorientierten Programmierung, sind aber bei größeren Projekten unumgänglich. Diese Kommentare zeichnen sich dadurch aus, dass sie immer mit /** beginnen und sich innerhalb der Kommentare Worte mit einem führenden @ befinden. Wir kommen im Anschluss an die Besprechung dieses Beispiels auf diese Kommentare zurück. Nehmen Sie diese Kommentare zurzeit als schmückendes Beiwerk.
388
Sandini Bib Zusammenspiel der Objekte
Die Klasse wird eingeleitet durch die Definition der Attribute. Diese sind in diesem Fall alle private. Es kann also keine Klasse, Funktion oder andere Anweisung auf diese Daten zugreifen. Im Konstruktor __construct werden nur Name, Vorname und Geburtstag mit Übergabewerten belegt. Zusätzlich wird eine neue Instanz (ein neues Objekt) der Klasse „AufenthaltContainer“ erzeugt: $this->_AufenthaltContainer = new AufenthaltContainer();
Um Werte ohne den Konstruktor setzen zu können, existieren mehrere Methoden, die mit set... beginnen. In einer solchen Methode können die Übergabeparameter daraufhin getestet werden, ob sie auch den Daten entsprechen, die für dieses Attribut verlangt werden. Die Methode setGeburtstag() aus Listing 7.27 und Listing 7.28 zeigt dies exemplarisch. Der Übergabeparameter $newVal wird mit einem regulären Ausdruck (regular Expression) daraufhin abgeprüft, ob die Zeichenkette aus zwei Zahlen, einem Punkt, noch zwei Zahlen und einem Punkt und schlussendlich vier Zahlen besteht. Dies ist zwar kein hundertprozentiger Schutz (der 45.98.9854 ist demnach gültig), aber als erster Ansatz brauchbar. Bei regulären Ausdrücken handelt es sich um ein sehr mächtiges Hilfsmittel bei der Überprüfung von Werten. In PHP gibt es zwei Varianten von regulären Ausdrücken. Die POSIX-konformen Ausdrücke werden mit Funktionen bearbeitet, die mit ereg... beginnen. Funktionen für die Bearbeitung von Perl-kompatiblen regulären Ausdrücken beginnen mit preg_. public function setGeburtstag( $newVal ) { if ( preg_match( "/^\d\d\.\d\d\.\d\d\d\d$/", $newVal ) ) { $this->_Geburtstag = $newVal; } else { throw new Exception ( "Geburtstag muss TT.MM.YYYY sein.", 10000); } }
Listing 7.27 Die Methode setGeburtstag aus Listing 7.28
Bei dem regulären Ausdruck aus Listing 7.27 handelt es sich also um einen Perl-kompatiblen Ausdruck. Die Suchmuster solcher Ausdrücke werden durch / gebunden. Das Zeichen ^ steht für den Beginn einer Eingabezeile, das Zeichen $ für dessen Ende. Innerhalb dieser Begrenzungen steht das \d für eine Zahl. \D ist das Synonym für Buchstaben. Da der Punkt die Bedeutung für Folgezeichen hat, muss ein realer Punkt im Muster durch \. dargestellt werden.
389
Sandini Bib 7 Objektorientierte Programmierung
Das Muster Datum dar.
"/^\d\d\.\d\d\.\d\d\d\d$/"
stellt also so etwas wie ein
Sollte der Übergabeparameter $newVal diese Bedingung nicht erfüllen, tritt eine neue Konstruktion aus PHP 5 auf den Plan: Ausnahmen. Bei den Ausnahmen handelt es sich um eine Klasse, von der mit new ein neues Objekt erzeugt wird. Dieser Klasse werden ein Fehlertext und eine Fehlernummer übergeben. Da es sich bei Exception um eine Klasse handelt, können Sie sich eigene Ausnahmeklassen erstellen, die alle Eigenschaften dieser Klasse erben. Sobald eine Ausnahme geworfen wird (throw), unterbricht der PHP-Interpreter das Programm an dieser Stelle und bewegt sich in der Hierarchie der Aufrufe so lange nach oben, bis diese Ausnahme aufgefangen (catch) wird. Sollte es keine Fangvorrichtung geben, bricht das Programm mit einer Fehlermeldung über eine nicht aufgefangene Ausnahme ab. Im Hauptprogramm (Listing 7.33) werden die Ausnahmen der benutzten Klassen aufgefangen. Listing 7.28 Die komplette Personen-Klasse
Wie Sie an dieser Klasse sehen können, kann eine recht einfache Klasse einen recht umfangreichen Quellcode zur Folge haben.
7.3.3 Die Klasse AufenthaltContainer Die Klasse AufenthaltContainer bringt nicht viel Neues. Mit den Kenntnissen der Klasse Person sollte diese Klasse kein Geheimnis mehr verbergen.
In der Methode addItem() wird die Anzahl der Einträge im Array $_Liste berechnet und dem Attribut $_Anzahl übergeben. Dies könnte eigentlich bei jedem Aufruf der Methode getAnzahl() geschehen. Da die Anzahl der Einträge aber sicherlich öfter aufgerufen wird, gewinnt man durch diese Vorgehensweise etwas an Geschwindigkeit. Die Methoden delItem() und Suche() wurden nicht realisiert, da sie im weiteren Verlauf nicht benötigt werden.
396
Sandini Bib Zusammenspiel der Objekte
7.3.4 Die Klasse Aufenthalt In der Methode addDiagnose() der Klasse Aufenthalt wird PHP mitgeteilt, welche Art an Übergabeparameter überhaupt erlaubt ist. In diesem Fall muss der Übergabeparameter der Klasse Diagnose entsprechen. Wenn dies der Fall ist, wird dieses Objekt dem Array $_Diagnosen hinzugefügt. Auch hier sehen Sie, Arrays können mehr, als man erst einmal erwartet.
7.3.5 Die Klasse Diagnose In der Klasse Diagnose wird eine einzelne Diagnose gekapselt. Diese wird aufgrund ihres Gültigkeitszeitraums typischerweise aus einer Datenbank ermittelt und in dieser Klasse den anderen Klassen zur Verfügung gestellt. Es handelt sich um eine sehr einfache Klasse. In der funktionsorientierten Programmierung werden solche Datenstrukturen durch struc oder record dargestellt. In PHP könnte man dafür ein Array einsetzen. Wenn Sie die Probleme solcher Strukturen kennen, werden Sie die Sicherheit solcher Klassen wie Diagnose bei größeren Projekten schätzen.
399
Sandini Bib 7 Objektorientierte Programmierung
Listing 7.31 Die komplette Klasse Diagnose
7.3.6 Die Klasse Abrechnung Die Klasse Abrechnung dient der Ermittlung des Rechnungsbetrages für den Aufenthalt. Dem Konstruktor wird hierfür das betreffende Objekt für den Aufenthalt übergeben. Dieses Objekt wird in der Variablen $_Aufenthalt gespeichert. Die Rechnung wird mit der Methode ErstelleRechnung() aufgebaut. In dieser Methode werden zwei Methoden aufgerufen, die als private deklariert sind. Diese Methoden sind also von außen nicht ansprechbar. Neben der Methode createBillNo(), die klassenintern eine Rechnungsnummer erstellt, kann diese auch extern durch die Methode setAbrechnungsnummer() gesetzt werden. Sollte es schon eine Rechnungsnummer geben, wird createBillNo() nicht aufgerufen. Mit dem Attribut DRG aus dem Objekt $_Aufenthalt kann dann der Rechnungsbetrag ermittelt werden. Diese umfangreiche Berechnung wird hier nicht durchgeführt. Listing 7.32 Die komplette Klasse Abrechnung
7.3.7 Das zusammengesetzte Puzzle Nachdem alle Klassen existieren, stellt sich die Frage, wie man daraus ein lauffähiges Programm erstellt. Dies soll in diesem Kapitel durchgeführt werden. Da sich die Eingabemasken alle ähneln, beschränken wir uns hier auf das Formular für die Eingabe der Personaldaten. In Abbildung 7.3 sehen Sie ein Eingabeformular für eine Browseroberfläche. Die Sternchen an der linken Seite einer Eingabezeile weisen auf Felder hin, die auf jeden Fall ausgefüllt werden müssen, so genannte Pflichtfelder. Der Geburtstag kann aus Pull-down-Menüs zusammengesetzt werden. Zusätzlich werden die maximal möglichen Zeichen für jedes Feld angegeben. Insgesamt scheint es sich um ein recht kompliziertes und umfangreiches HTML-Formular zu handeln. Wie Sie im Folgenden sehen werden, hält sich der Aufwand für ein solches Formular in Grenzen. Vorausgesetzt, man weiß wie. Wenn Sie den Button ABSENDEN anklicken, werden die Daten verarbeitet. Innerhalb des Programms sind einige Klassen/Objekte „per Hand“ gesetzt, um nur mit dieser einen Maske die Möglichkeiten von PHP in diesem Bereich zu zeigen. Die Ausgabe des Programms sehen Sie in Abbildung 7.4.
404
Sandini Bib Zusammenspiel der Objekte
Abbildung 7.3 Eingabe in die QuickForm-Maske
Das Programm zu diesem Formular finden Sie in Listing 7.33. Es beginnt als normale HTML-Seite und endet nach der Überschrift . Im PHP-Programm wird an erster Stelle eine PEAR-Bibliothek eingebunden: HTML_QUICKFORM. Wie der Name vermuten lässt, kann man mit den Methoden dieser Klassenbibliothek recht schnell ansehnliche Formulare generieren. Die einzelnen Methoden der Klasse „QuickForm“ werden Sie im nächsten Kapitel genauer kennen lernen. Die Namen der Methoden sind allerdings recht sprechend, so dass Sie den Verlauf des Programms verfolgen können, zumal die gesamte Verarbeitung in die Funktion data_processing() ausgelagert ist. Diese Funktion finden Sie am Ende von Listing 7.33. Dieser Funktion wird ein Array mit den Werten aus dem Formular übergeben. Am Beginn der Funktion werden diese Formularwerte einzelnen Variablen des PHP-Programms zugeordnet.
405
Sandini Bib 7 Objektorientierte Programmierung
Abbildung 7.4 Ergebnis des Programms aus Listing 7.33
Listing 7.33 Das Programm zum Test der Klassenstruktur
Eingabe der Personaldaten
Personaldateneingabe
In dieser Maske können Sie die Personaldaten eingeben.
Das Geburtsdatum muß zwischen 1890 und 2004 liegen.
Ihre Eingaben waren wie folgt:
Nach der Zuordnung der Formularwerte wird ein try-Block begonnen. Bei diesem Block handelt es sich um die Verarbeitung der neuen Ausnahme-Fehlerbehandlung. Alle Klassen, Funktionen etc., die zwischen try und catch eine Ausnahme „werfen“, können im catch-Block bearbeitet werden. Innerhalb des try-Blocks wird als Erstes das Objekt $patient aus der Klasse person erstellt und mit Werten versorgt. Dabei wird darauf geachtet, ob aus dem Formular auch Daten der optionalen Felder geliefert werden. Nur dann können die entsprechenden Attribute des Objektes mit diesen Werten versorgt werden. Um nicht zu viel zu schreiben, wird der Weg zur Aufenthaltsliste von $patient in der Variablen $list zwischengespeichert. Danach werden zwei Aufenthalte erzeugt und jeweils mit der Methode addItem() im Objekt gespeichert. Die Variable $list wird anschließend mit unset() aus dem Speicher gelöscht. Die hinzugefügten Werte verbleiben im Objekt $patient. Dies können Sie prüfen, wenn Sie an dieser Stelle die Funktion var_dump() für dieses Objekt einfügen und das Programm laufen lassen. Sollte auf dem Weg hierhin eine Ausnahme aufgetreten sein, wird Sie im folgenden catch()-Block als Text ausgegeben.
410
Sandini Bib Die Klasse HTML_QuickForm
In den folgenden Zeilen werden die eingegebenen Werte für dieses Objekt einfach wieder ausgegeben. Dabei werden verschiedene Wege gegangen. Vom einfachen Aufruf der get...-Methoden einer Klasse bis hin zum Aufruf $visit_list = $patient->getAufenthalte()->getListe();
der sich über zwei Klassenebenen hinwegbewegt. Mit $patient>getAufenthalte() bekommen Sie die instanziierte Klasse AufenthaltContainer der Klasse person (Objekt $patient). Über den AufenthaltContainer bekommen Sie wiederum die einzelnen Aufenthalte. In der darauf folgenden zählergesteuerten Schleife werden die Aufenthaltsnummern ausgegeben, die weiter oben im Programm dem Objekt $patient zugeordnet wurden. Wer sich schon einmal mit der objektorientierten Sichtweise anderer Programmiersprachen beschäftigt hat, sieht, dass sich PHP in dieser Hinsicht mit der Version 5 in das Lager der objektorientierten Sprachen begeben hat.
7.4
Die Klasse HTML_QuickForm
Im Beispielprogramm des letzten Kapitels haben wir von der Klasse „HTML_QuickForm“ aus dem PEAR-Packet von PHP Gebrauch gemacht. Im Folgenden werden Sie einen ersten Eindruck der Möglichkeiten dieser Klasse bekommen. Dazu verwenden wir das Programm aus Listing 7.33. Im letzten Kapitel habe ich Ihnen die Erklärung der einzelnen Anweisungen vorenthalten. Schauen wir uns das Programm unter diesem neuen Gesichtspunkt noch einmal an. Damit Sie nicht ständig hin und her blättern müssen, finden Sie das HTML-Formular noch einmal als Abbildung 7.6 wieder. Bevor Sie mit der Klasse „HTML_QuickForm“ arbeiten können, müssen Sie diese Klasse erst einmal auf Ihren Computer kopieren. Wenn Sie das grundlegende PEAR-Packet installiert haben (siehe Installations-Kapitel l), gestaltet sich die Installation sehr einfach.
411
Sandini Bib 7 Objektorientierte Programmierung
Abbildung 7.5 Installation von HTML_QuickForm über die Kommandoebene
Bevor Sie „HTML_QuickForm“ installieren können, müssen Sie die Klassen des Paketes „HTML_Common“ installieren. In Abbildung 7.5 finden Sie zusätzlich noch die Installation zweier weiterer Pakete, die einem gute Dienste leisten können: Auth und Auth_HTTP. Was PEAR meldet, wenn es eine Abhängigkeit von Paketen nicht auflösen kann, sehen Sie in der Mitte der Abbildung 7.5 beim ersten Aufruf zur Installation des Pakets Auth_HTTP. Aus dem Namen eines PEAR-Paketes können Sie auf den Speicherort innerhalb des PEAR-Dateienbaumes schließen. Sie müssen den Unterstrich „_“ nur durch ein „/“ ersetzen. Die Quellen zu „HTML_ QuickForm“ finden Sie also im Unterverzeichnis HTML des PEAR-Verzeichnisses. Um mit QuickForm zu arbeiten, müssen Sie als Erstes ein Objekt dieser Klasse erstellen. Dies können Sie mit $form = new HTML_QuickForm( "Personaleingabe", "post" );
erreichen. Hierbei wird ein Formular mit dem Namen Personaleingabe erstellt. Dieser Name hat nichts mit der Überschrift aus Abbildung 7.5 zu tun! Die Daten des Formulars werden mit der POST-Methode verschickt. Sie können an dieser Stelle auch ein get angeben, wodurch diese Methode zur Übermittlung der Daten benutzt wird.
412
Sandini Bib Die Klasse HTML_QuickForm
Ein Textelement können Sie in diesem Formular durch die Anweisung $form->addElement( "text", "name", "Nachname (max. 50)" );
erstellen. Das Textelement bekommt den Namen name. Über diesen Namen können Sie später im PHP-Programm auf die eingegebenen Werte dieses Textfeldes zugreifen. Sie sollten also jedem Textfeld einen anderen Namen geben. Dass es sich hierbei um ein Textfeld handelt, bestimmen Sie mit der Angabe "text" als ersten Parameter. Abbildung 7.6 HTML_QuickForm-Maske
Bei Datumsangaben gilt es, die Gewohnheiten des Benutzers zu beachten. In Deutschland haben viele Personen mit der Datumsangabe 03/05/ 2004 Probleme. Was ist jetzt der Tag und was der Monat? Oder man kennt dieses Format gar nicht und geht stillschweigend von einer deutschen Datumsangabe aus. Das kann zu schwerwiegenden Problemen führen. Glücklicherweise kann man „HTML_QuickForm“ dazu bringen, die Datumsangaben in bekannter Form entgegenzunehmen und auch abzuliefern. Dazu müssen Sie ein Array mit den entsprechenden Werten füllen:
413
Sandini Bib 7 Objektorientierte Programmierung
$birthd_options = array( 'language'
=> 'de',
'format'
=> 'd.m.Y',
'minYear'
=> 1890,
'maxYear'
=> 2004
);
In diesem Beispiel geben Sie die Sprache Deutsch an, das Datumsformat und die Grenzen der Jahresangaben, die noch akzeptiert werden. Das Format „d.m.Y“ entspricht dem deutschen Standard. So wird der 1. Februar 2004 als 01.02.2004 geliefert. Die Datumsabfrage selber wird mit $form->addElement("date", "birthd", "Geburtstag", $birthd_options );
in das Formular integriert. Durch das "date" im ersten Parameter erzeugen Sie ein Datumsfeld. Bisher erscheinen alle Felder untereinander. Wenn Sie aber Felder nebeneinander anordnen wollen, wie das bei Buttons üblich ist, müssen Sie einen kleinen Umweg gehen. Sie erzeugen ein Array, dem Sie die Formularelemente als Referenz übergeben. Dabei werden die einzelnen Felder über die Klassenmethode createElement() erzeugt. Für die beiden Buttons aus Abbildung 7.5 verwenden Sie die folgenden Zeilen: $buttons[] = &HTML_QuickForm::createElement( 'reset', 'btnClear', 'Löschen'); $buttons[] = &HTML_QuickForm::createElement( 'submit', 'btnSubmit', 'Absenden'); $form->addGroup($buttons, null, null, ' ');
Sie können mit „HTML_QuickForm“ alle Elemente eines HTML-Formulars erstellen. Schauen Sie in die Dokumentation zu diesem Paket (zu finden unter PEAR). Aber Sie können nicht nur Felder erzeugen und darstellen, sondern deren Inhalt testen und gegebenenfalls in das Formular zurückspringen. Bevor Sie testen, können Sie die Formularwerte vorverarbeiten. Sollte der Anwender beispielsweise Leerzeichen am Beginn oder am Ende des Feldes eingegeben haben, sind diese bei der Suche innerhalb einer Datenbank mehr als lästig. Um diese Leerzeichen zu entfernen, müssen Sie jetzt nicht bis zu Ihrer Verarbeitung der Daten warten. Sie können mittels $form->applyFilter("name", "trim");
414
Sandini Bib Die Klasse HTML_QuickForm
die Angaben im Feld name durch die PHP-Funktion trim() entfernen. Statt der Funktion trim() können Sie natürlich auch jede weitere sinnvolle Funktion verwenden. Pflichtfelder innerhalb des Formulars können Sie mit $form->addRule("name", "Der Nachname ist zwingend.", "required" );
bestimmen. Hierbei geben Sie als ersten Parameter den Namen des Feldes an, gefolgt von der Meldung, die erscheinen soll, wenn dieses Feld vergessen wird. Über die Angabe "required" wird dieses Feld zum Pflichtfeld. Wenn Sie die Länge eines Feldes begrenzen wollen, so können Sie dies über den Aufruf $form->addRule("name", "Der Nachname darf maximal 50 Zeichen haben." , "maxlength", 50 );
erreichen. Wenn Sie "maxlength" durch "minlength" ersetzen, bekommen Sie einen Test auf die Mindestlänge einer Eingabe. Wenn Sie auf diese Weise Ihr Formular zusammengebaut haben, können Sie die Eingaben über den Aufruf $form->validate() testen. Sollte dabei ein Fehler entdeckt werden, kann „HTML_QuickForm“ zurück in die Eingabemaske springen. Sind alle Angaben ordnungsgemäß eingegeben worden, werden diese Eingaben „eingefroren“ und an eine Funktion Ihrer Wahl übergeben. In unserem Beispiel handelt es sich um die Funktion data_processing(), die wir schon besprochen haben. Die Logik kann über eine if-Abfrage realisiert werden: if ( $form->validate() ) { $form->freeze(); $form->process('data_processing', false); } else { ?> In dieser Maske können Sie die Personaldaten eingeben.
Das Geburtsdatum muss zwischen 1890 und 2004 liegen.