In diesem Teil soll die Objektorientierte Programmierung (kurz OO bzw. OOP) allgemein erklärt werden. Im nächsten Teil kommt dann die Realisierung in PHP.
Die ersten Beispielprogramme, die im Verlauf dieses Manuals besprochen wurden, hatten keine große Struktur: In ihnen wird einfach am Anfang des Programmes angefangen und am Ende aufgehört. Teilweise wird mit if & Co. ein wenig hin und her gesprungen. Das Ganze wird allerdings schnell unübersichtlich und Teile lassen sich nur durch Cut'n'Paste wieder verwenden.
Bei der Programmierung mit Funktionen wird das ganze schon etwas übersichtlicher. Es gibt Funktionen, die bei einem Aufruf mit den übergebenen Werten etwas machen. Diese Funktionen lassen sich in diverse Dateien ausgliedern und können dadurch in mehreren Programmen wieder verwendet werden. Allerdings können die Funktionen untereinander (über den eigentlichen Funktionsaufruf hinaus) keine Werte austauschen, das heißt die Werte müssen alle über das aufrufende Programm gehen.
Bei der Objektorientierung ist man einen Schritt weiter gegangen und hat die Daten und die Funktionen zusammengefaßt, so daß man sie nun als eine Einheit betrachtet. Im Prinzip hat man damit versucht, die reale Welt abzubilden. Konkret heißt das, daß in einer solchen Einheit, Klasse genannt, die Funktionen (hier Methoden genannt) auf gemeinsame Daten (Attribute, Klassen- oder Instanzvariablen genannt) zugreifen können.
Wenn wir uns jetzt vorstellen, das Ganze mit Funktionen nachzubauen, hätten wir ein Problem: Wir könnten zwar Funktionen wie setTime() oder setAlarm() programmieren, könnten die Werte aber nicht speichern (auf globale Variablen wollen wir unter anderem des guten Programmierstils wegen verzichten). Bei einem Objekt gibt es das Problem nicht, denn dieses besitzt das Attribut Uhrzeit und kann diese mit Hilfe der Methode setTime() nach einer Plausibilätsprüfung setzen. Das Beispiel Funkwecker hinkt natürlich etwas, da Objekte im Hintergrund nicht einfach weiterlaufen und damit z.B. die Weckfunktion nicht funktionieren würde.
Während die DSP-Werke die Pläne für die Konstruktion von Autos des Modells DSP CR haben, haben wir als Besitzer eines DSP CR nur genau ein Exemplar, können also selbst keine weiteren Exemplare herstellen. Uns interessiert auch gar nicht, wie der Fertigungsprozeß aussieht - wir wollen ja nur mit dem Auto fahren, es also benutzen. Alles, was wir dazu kennen müssen, ist die Schnittstelle des DSP CR: Wie startet man den Wagen, wie beschleunigt, bremst, schaltet und lenkt man?
An dieser Stelle kann man schon etwas sehr grundlegendes der Objektorientierung feststellen: Durch die Kapselung der Funktionalität erreicht man, daß man diese problemlos optimieren kann, solange man nur die Schnittstelle unverändert läßt und natürlich am zu erwartenden Ergebnis einer Funktion nichts verändert (wenn man bisher immer beschleunigt hat, wenn man aufs Gaspedal getreten hat, wäre man sicher mehr als überrascht, wenn die DSP-Werke in der nächsten Modellgeneration einfach die Bremse mit dem Gaspedal verbinden würden ...). Auch sollten Eigenschaften grundsätzlich nur über die Schnittstelle abruf- und veränderbar sein, damit etwaige Änderungen an der Art, wie etwas gelöst wurde, jederzeit vorgenommen werden können, ohne weitere Abhängigkeiten verfolgen zu müssen.
Doch zurück zum Autofahren: Wir erwarten also von unserem Wagen, daß er sich wie ein ganz normales Auto verhält. Den DSP-Werken überlassen wir es, die gewünschte Funktionalität zur Verfügung zu stellen (d.h. einzubauen). Wir wollen aber vielleicht nicht nur einen Wagen haben, sondern doch lieber zwei - z.B. einen für jeden Ehepartner. :-) Die beiden Wagen sollen aber natürlich nicht genau gleich sein, das wäre ja langweilig. Wir sagen den DSP-Werken also beim Bestellen des Zweitwagens gleich, daß wir diesmal keinen Standard-Silbermetallic-CR haben wollen, sondern lieber einen dunkelgrünen CR in der Family-Ausführung. Innerhalb der DSP-Werke ist für diese Bestellung der Konstruktor zuständig: Er nimmt die Daten auf und sorgt dafür, daß diese allen daran interessierten Fabrikationsstationen des Werkes in der einen oder anderen Form zur Verfügung gestellt werden.
Nun stellen die DSP-Werke im Wesentlichen natürlich DSP-Modelle her. Sicher gibt es aber auch den einen oder anderen Extra-Dienst, der nicht direkt abhängig von einem Wagen ist, jedoch sinnvollerweise von den DSP-Werken angeboten wird. Auf diesen Extra-Dienst soll jeder Außenstehende zugreifen können - egal, ob er einen DSP CR hat oder nicht. Vielleicht will der DSP-Konzern aber auch einfach nur eine Sonderaktion starten und für begrenzte Zeit ein Logo auf jeden gefertigten DSP CR sprühen lassen. Die beiden Fälle scheinen auf den ersten Blick völlig unterschiedliche Problematiken zu beschreiben, aber sie haben eine Gemeinsamkeit: Sie sollen beide auch indirekt von jedem Besitzer eines DSP CR aufruf- bzw. veränderbar sein. Logischerweise dürfen Extra-Dienste der DSP-Werke auf keine Eigenschaften von DSP-Modellen zugreifen, denn wenn ein solcher Dienst von jemandem erbeten wird, der keinen DSP CR besitzt, dann kann auch an keinem DSP CR eine Veränderung durchgeführt werden - nicht einmal die Abfrage von Daten eines DSP-Modells ist erlaubt!
|
Bezogen auf das obige Auto-Beispiel könnten z.B. die DSP-Werke ein neues Modell DSP CR-JH herausbringen wollen. Der Einfachheit halber nehmen sie dazu die Pläne des DSP CR, ergänzen hier und ändern da etwas - das neue Modell basiert ja auf dem erfolgreichen DSP CR. Ebenso ist der DSP CR im Grunde auch nur ein Auto, also warum für jedes Modell das Rad neu erfinden? ;-) Denkbar ist doch, daß irgendwo in den Tiefen des DSP-Archivs schon ein Plan für ein Ur-Auto liegt, der wieder herausgekramt werden kann, wenn alle Ideen des Modells CR verworfen werden müßten - niemals aber die Grundidee des Autos!
Es gibt die Unterscheidung zwischen dem Standardkonstruktor und dem Allgemeinen Konstruktor. Während ersterer parameterlos und dadurch eindeutig bestimmt ist, erwartet letzterer mindestens einen Parameter und ist dadurch allgemein brauchbar (daher die Bezeichnung). ,,Allgemeiner Konstruktor`` ist natürlich nur ein Oberbegriff für alle Konstruktoren außer dem Standardkonstruktor.
PHP kennt allerdings bisher leider keine Destruktoren. Man kann sich über die Funktion register_shutdown_function() einen Behelf zusammenbauen oder sich PHP 5 anschauen. ;-)
Bei unserem obigen Image-Beispiel müssen die genannten Methoden public sein (sonst würden sie keinen Sinn machen). Die Attribute wie z.B. width oder height, die über init() gesetzt werden, sollten nicht auf public gesetzt werden, damit nicht jeder an sie heran kommt. Wenn sie nun in der Klasse ,,Image`` auf private gesetzt würden, hätten wir keine Möglichkeit, aus der Klasse ,,Point`` darauf zuzugreifen. Wenn dies gewünscht ist, müssen sie auf protected gesetzt werden.
Wem dies jetzt zu viel war, der kann sich beruhigt zurücklehnen und aufatmen: PHP 4 kennt noch keine Unterscheidung zwischen public, private und protected. Es ist einfach alles public. Da sich das jedoch mit PHP 5 definitiv ändern wird (siehe 20.5), sollte man sich zumindest grundlegende, grobe Gedanken machen und z.B. alle Methoden, die ausschließlich von der Klasse selbst (oder erbenden Klassen) und nur intern benutzt werden, an das Ende der Klasse verfrachten und für private oder protected vormerken, z.B. durch Kennzeichnung mittels einem (keinesfalls zwei!) vorangestelltem Unterstrich - gilt auch für Attribute.