PHP - Opjekt orientiertes Programmieren

Page 1

OOP mit PHP5 - Einführung 1. Hinweis Auf vielfältigen Wunsch hin habe ich den Bereich OOP jetzt direkt in die Theorie von PHP integriert und nicht wie bisher als eigenständigen Punkt geführt. Allerdings sollten sich die Anfänger unter euch erst dann auf diesen Bereich stürzen, wenn sie alle Grundlagen von PHP und MySQL beherrschen. Vorher ist das ziemlich sinnfrei. Wer sich wundert, dass hier das Ein oder Andere fehlt, dem sei gesagt, ja weiß ich. Kommt noch. 2. Ein Wort in eigener Sache Warum macht sich eigentlich jemand die Mühe und verfasst noch mal eine Einführung zum Thema "Objektorientierte Programmierung mit PHP 5"? Davon gibt es doch Massen im Internet. Nun, ursprünglich hatte ich das gar nicht vor. Als ich Mitte des letzten Jahres anfing, mich intensiv mit diesem Thema zu beschäftigen, musste ich feststellen, dass eigentlich fast alle Anleitungen zu diesem Thema für Nicht-Informatiker kaum verständlich sind. Ein paar Beispiele gefällig? "Das Ablegen einer Referenz auf ein anderes Objekt in einer Instanzvariablen eines Objektes nennt man Aggregation." "Leitet ein Objekt einen Methodenaufruf an ein aggregiertes Objekt weiter, so spricht man von Delegation." [Quelle: Sebastian Bergmann, Professionelle Softwarentwicklung mit PHP5]

"Klassenmember oder -methoden als statisch zu deklarieren macht diese zugänglich, ohne dass man die Klasse instantiieren muss. Auf ein als statisch deklariertes Member kann nicht mit einem instantiierten Klassenobjekt zugegriffen werden." [Quelle: Handbuch PHP, Kapitel Klassen und Objekte (PHP 5)] Alles klar? Begriffen? Kein Wunder! Selbst ich habe des Öfteren nur Bahnhof verstanden. Schuld daran ist nicht nur dieses fürchterliche Informatikerdeutsch, sondern auch die unterschiedliche Benamung von ein und denselben Dingen. Zur Entschuldigung von Sebastian Bergmann sei gesagt, der schreibt nicht nur so, der redet auch so. Habe ihn mal auf einem Multimediatreff in Köln kennen gelernt. Und über das "Deutsch" von Kreativen und Marketingexperten will ich ja erst gar nicht reden. So habe ich mir denn mal die Mühe gemacht, dieses krude Deutsch für euch zu übersetzen und in eine für Anfänger einigermaßen verständliche Form zu bringen. So gibt es den nun eine weitere Einführung in die Objektorientierte Programmierung mit PHP5. 3. Warum Objektorientierte Programmierung? Um diese Frage zu beantworten, muss ich erst mal auf die unterschiedlichen Programmierstile eingehen, die in PHP möglich sind. Das sind, einfach gesagt, deren drei. Bitte verwechselt das nicht mit dem so genannten Programmierparadigma. Auch weise ich wie so oft darauf hin, dass die folgenden Begriffe meinem Hirn entsprungen sind. Unstrukturierte Ablaufsteuerung Dies ist der klassische Anfängerstil. Nicht böse sein, auch bei mir lief es zu Beginn so. Man fängt oben an und "programmiert" sich dann nach unten durch. Die gesamte Steuerung erfolgt ausschließlich über Bedingungen. Die Nachteile sind offensichtlich. Dieser Code wird für eine ganz bestimmte Aufgabe entwickelt, und nur dafür! Man kann ihn nicht für andere Projekte einsetzen. Wenn innerhalb der Programmierung etwas mehrmals erledigt werden soll, so muss der entsprechende Code dupliziert und angepasst werden. Änderungen dieser Abschnitte haben Auswirkung auf alle(!) relevanten Codeteile. Strukturierte und funktionsbasierte Steuerung Dieser Stil ist bereits ein gewaltiger Fortschritt und erfahrungsgemäß die nächste Stufe auf der Evolutionsleiter der Programmierung. Hier werden alle wichtigen Aufgaben in Funktionen ausgelagert, die man dann über entsprechende Parameter ansteuert. Der Vorteil ist offensichtlich. Ändern sich grundsätzliche Dinge, so muss man nur noch die Funktionen umschreiben und alles läuft. Die Nachteile sind trotzdem noch gravierend. Auch Funktionen


sind meist für spezielle Aufgaben entwickelt worden und können in anderen Projekten nur durch Anpassungen(!) wieder verwendet werden. Und bei größeren Projekten mit verschiedenen Entwicklern endet das ganz schnell in einem riesigen Tohuwabohu Objektorientierte Programmierung (OOP) Um die oben beschriebenen Nachteile zu umgehen, setzt man die Objektorientierte Programmierung ein. Sie ermöglicht es, immer wiederkehrende Aufgaben in so genannten Klassen zu bündeln. Für den Benutzer ergeben sich bei sauberer(!) Programmierung daraus gewaltige Vorteile:

• Klassen sind so konzipiert, dass man ihre innere Logik nicht kennen muss, um sie zu nutzen

• Modifikationen, die die innere Steuerung der Klassen betreffen, haben keine Auswirkung auf den übrigen Code

• Klassen werden so entwickelt, dass sie jederzeit wieder verwendet werden können • Klassen können durch das Vererbungsprinzip modular erweitert werden • Klassen beinhalten bereits eine Fehlerroutine 4. Was benötigt man für Objektorientierte Programmierung? Erfahrung und entsprechende Vorkenntnisse in der strukturierten und funktionsbasierten Programmierung. Es gibt zwar immer wieder Leute, die behaupten, dass für Einsteiger die OOP besonders leicht zu lernen sei, da dieses Prinzip selbsterklärend ist. Ich persönlich habe da aber große Zweifel. Also, wenn ihr Anfänger seid, und noch nicht mal strukturiert mit Funktionen programmieren könnt, so lernt doch bitte erst mal das und kommt dann wieder. 5. OOP - Der Stein der Weisen? Nein! Nicht Alles, was man programmieren kann, muss objektorientiert sein. Für ganz spezielle Aufgaben ist die normale prozedurale Vorgehensweise oft einfacher, besser und schneller. Die Feinheiten werdet ihr im Laufe der Zeit selber kennen lernen. 6. Beispiele Aus Platzgründen werde ich hier nur Ausschnitte aus meinen Beispielen präsentieren. Wer es genau wissen will, lade sich doch bitte die funktionsfähigen Codeschnipsel rechts unter Beispiele herunter.


OOP mit PHP5 - Einführung - Begriffe 1. Das Beispiel ... ist ziemlich seltsam. Aber so bin ich halt. Wenn ich etwas anhand völlig idiotischer Beispiele erklären kann, so habe zumindest ich es selber verstanden. Ob andere damit klarkommen? Keine Ahnung, mal abwarten. 2. Dieter und Dörte In der Objektorientierten Programmierung (OOP) gibt es vier elementare Begriffe.

• das Objekt • die Klasse • die Eigenschaft • die Methode Um euch diese Begriffe und alles Weitere zu erläutern, gehen wir mal von folgendem Beispiel aus, das sich quer durch diese Einführung ziehen wird. Also, da gibt es einen Mann, nennen wir ihn "Dieter", und der ist total scharf auf eine Frau, sagen wir mal "Dörte". Um denn nun ihr Herz zu gewinnen (oder sie einfach nur ins Bett zu bekommen), will er sie zu einem romantischen Abendessen einladen. 3. Das Objekt Im Sinne der OOP handelt es sich bei diesen beiden Personen um OBJEKTE. Wenn die Verabredung per Telefon geschieht, so ist dies auch eines. Wenn Dieter seine Dörte mit einem Auto oder Taxi abholen will, so handelt es bei denen auch um Objekte. Wenn sie dann in einem Restaurant dinieren (Anm. d. Verf.: sauberes Deutsch für "Mampfen gehen"), so ist dieser Fresstempel auch eines. Objekte sind also programmiertechnisch gesehen irgendwelche Dinge. Genau so wie im richtigen Leben halt. 4. Die Klasse Durch Klassen werden Objekte erzeugt. Sie sind eine Art von Entwurfsmuster oder Bauplan, nach denen das Objekt aufgebaut ist. Wenn man also im richtigen Leben das Objekt "Dieter" erzeugen möchte, so benötigt man eine "Die Sache mit den Bienen und den Blumen"-Klasse für dessen Eltern. Oder für das Restaurant eine "Häusle baue"-Klasse für das Objekt Bauunternehmen. 5. Die Eigenschaft Diesen Begriff werde ich von nun an konsequent benutzen, da er meiner Meinung nach die beste Beschreibung ist. Andere nennen das auch "Instanzvariablen", "Attribut" oder "Member", wobei ich vor allem letzteren Ausdruck für äußert unglücklich halte. Also, jedes Objekt hat eine oder mehrere Eigenschaften, die den Zustand oder die Zustände von Selbigem festlegen. Wodurch unterscheiden sich nun Dieter und Dörte voneinander? Ganz einfach, durch ihr Geschlecht und ihren Namen. Es könnten auch noch viel mehr sein, aber das ignorieren wir einfach mal. Was für verschiedene Eigenschaften können Telefone haben? Das eine ist ein Handy, das andere ein stinknormales von der Telekom. Bei Letzterem könnte man noch unterscheiden zwischen Analog- oder ISDN-Telefon. 6. Die Methode Gottlob scheint dieser Begriff allgemein gültig zu sein. Dabei handelt es sich um Alles, was Objekte MACHEN können. Mit einem Auto kann man fahren, mit einem Telefon telefonieren, mit einer Frau ..., na ja vieles oder gar nichts. Will man zum Beispiel die Eigenschaften eines Objektes ändern, so benötigt man unter Umständen dafür Methoden.


OOP mit PHP5 - Grundlagen 1. Klassen Innerhalb von Klassen werden Eigenschaften und Methoden zu einer Einheit gebündelt. Das nennt man auch Kapselung und ist ein entscheidendes Prinzip der Objektorientierten Programmierung. Damit schafft man sich eine organisatorische Einheit, die leicht zu verwalten ist. Das Ganze geschieht mit class. Um zum Beispiel einen Entwurf vom Typ "Mensch" zu erzeugen, geht man so vor: class Mensch { ... }

2. Eigenschaften Dabei handelt es sich um spezielle Variablen, die innerhalb einer Klasse definiert werden. Wichtig dabei ist zu wissen, dass nicht alle Variablen Eigenschaften sind. Das gilt nur für diejenigen, die Auswirkungen auf den Zustand eines Objektes haben. Also nehmen wir mal "Dieter" bzw. "Dörte" und legen zwei Eigenschaften für das Geschlecht und den Namen fest. Um nicht vorzugreifen, benutze ich erst mal die alte PHP4-Schreibweise. class Mensch { var $geschlecht; var $namen; }

3. Methoden Um nun zum Beispiel diese Eigenschaften zu ändern, benötigt man Methoden. Das sind, einfach ausgedrückt, Funktionen in einer Klasse. class Mensch { var $geschlecht; var $namen; function setGeschlecht($wert) { $this -> geschlecht = $wert; } function setNamen ($wert) { $this -> namen = $wert; } } Die Peudovariable $this Damit kann ein Objekt auf seine EIGENEN Eigenschaften und Methoden zugreifen, also auf die Variablen und Funktionen. In diesem Fall ändern wir über Methoden (Funktionen) die Eigenschaften (Variablen).


4. Objekte Nun wollen wir zwei Objekte vom Typ Mensch erzeugen. Einmal den Mann "Dieter" und dann die Frau "Dörte". Das geschieht folgendermaßen: $dieter = new Mensch; $dieter -> setGeschlecht('männlich'); $dieter -> setNamen('Dieter'); $doerte = new Mensch; $doerte -> setGeschlecht('weiblich'); $doerte -> setNamen('Dörte');


OOP mit PHP5 - Grundlagen - Referenzierung 1. new Mit new erzeugt man eine Referenz auf ein Objekt. Das ist eine Art von Hinweis, die von PHP intern gesteuert wird, ähnlich wie bei Sessions. Die kann man nun jederzeit durch die entsprechende Variable ansteuern. In unserem Fall sind das $dieter und $doerte. Diese Referenzierung wird besonders deutlich durch die Schreibweise $dieter ->. Wir haben also zwei Objekte aus der Klasse Mensch erzeugt und bei jedem die Eigenschaften $geschlecht und $namen zugewiesen. 2. Wie komme ich an die Eigenschaften? Das hängt von der Sichtbarkeitsstufe ab (dazu später mehr). Bei einem Vollzugriff kann man so auf die Eigenschaften zugreifen: $dieter = new Mensch; $dieter -> setGeschlecht('männlich'); $dieter -> setNamen('Dieter'); // Zugriff auf die Eigenschaften echo $dieter -> geschlecht; echo $dieter -> namen; Wenn (in PHP5) der Vollzugriff nicht gestattet ist, so kann man zum Beispiel eine Methode definieren, die bei Bedarf die Werte zurückgibt. Aus didaktischen Gründen hauen wir die in ein Array, was man in dieser Form eigentlich nicht machen sollte: class Mensch { ... function returnInfo() { $info = array(); $info['geschlecht'] = $this -> geschlecht; $info['namen'] = $this -> namen; return $info; } } ... $dieter_info = $dieter -> returnInfo(); print_r($dieter_info); Jetzt werden sich sicher viele fragen, warum man hier nicht auch mit einer Eigenschaft ($this -> info) arbeitet. Nun, $info ist keine Eigenschaft. Es fasst nur welche in einem Array zusammen und gibt sie bei Bedarf zurück. Daher ist $info auch nur eine stinknormale lokale Variable in einer Methode. Allerdings sieht man hier, dass Methoden eine weitere Aufgabe haben. Sie dienen auch der KOMMUNIKATION. Ich weise euch aber schon mal darauf hin, dass man Klassen so programmieren kann (und soll), dass obiger Zugriff gar nicht nötig ist. Zu den Details komme ich später. 3. Variablenzuweisung PHP erlaubt uns, die Referenz, also den Verweis auf ein Objekt, in einer zusätzlichen Variablen abzuspeichern. Anfängern rate ich zwar von dieser Möglichkeit ab, ich zeige sie aber trotzdem.


$doerte = new Mensch; $doerte_tmp = $doerte; $doerte_tmp -> setGeschlecht('weiblich'); Nicht sehr schön, nicht sehr fein, aber es funktioniert. Um nun zu überprüfen, ob $doerte und $doerte_tmp auf dasselbe Objekt verweisen, kann man das so testen: if ($doerte === $doerte_tmp)

4. Klonen Ist in der Praxis im Moment nur mit Schafen, Mäusen und anderem Getier möglich. Programmiersprachen sind das schon ein wenig weiter. Und wozu? Mal abgesehen von den ethischen Problemen könnte im Laufe der Programmierung eine Situation eintreten, die das erfordert. Ich will das mal an einem zugegebenermaßen saudummen Beispiel erläutern. Wir wollen objektorientiert das Balzverhalten von "Dieter" anhand seines Geschlechts erfassen. So, irgendwann stellt der fest, dass er doch eigentlich eine Frau sein möchte und lässt eine Geschlechtsumwandlung vornehmen. Nun könnte man einfach auf die Idee kommen, seine Eigenschaft $geschlecht zu ändern. Dann hätten wir aber keine Möglichkeit mehr, alles zu erfassen, was vorher passiert ist. Also wo er noch ein Mann war. So "klonen" wir ihn denn, um seinen weiteren Werdegang zu beobachten. Das geschieht mit dem Schlüsselwort clone. $dieter = new Mensch; $klon = clone $dieter; Was ist mit den Eigenschaften? Wenn ein Objekt geklont wird, so hat es zu diesem(!) Zeitpunkt dieselben Eigenschaften wie das Original. Ändert man nun selbige, so hat das nur Auswirkungen auf das geklonte Objekt und nicht auf das Original! // Objekt Dieter mit Eigenschaften $dieter = new Mensch; $dieter -> setGeschlecht('männlich'); $dieter -> setNamen('Dieter'); // Klon von Dieter, selbe Eigenschaftem $klon = clone $dieter; $klon_info = $klon -> returnInfo(); print_r($klon_info); // Änderung der Eigenschaften des Klons $klon -> setGeschlecht('weiblich'); $klon -> setNamen('Dietlinde'); $klon_info = $klon -> returnInfo(); print_r($klon_info); // Eigenschaften von Dieter bleiben erhalten $dieter_info = $dieter -> returnInfo(); print_r($dieter_info);


Was ist mit den Methoden? Nat端rlich kann ein geklontes Objekt auf dieselben(!) Methoden zugreifen wie das Original. Das seht ihr an obigem Beispiel. $klon_info = $klon -> returnInfo();


OOP mit PHP5 - Grundlagen - Sichtbarkeit Kommen wir nun zum Punkt der "Sichtbarkeit". Erinnert ihr euch an den Geltungsbereich von Variablen in Funktionen. Da wo man auf Variablen nur in einem bestimmten Zusammenhang zugreifen konnte? Dies hier ist eine erweiterte Form der Zugriffsbeschränkung, die man selber steuern kann. Leider muss ich jetzt allen PHP4Nutzern mitteilen, dass für sie an dieser Stelle endgültig Schluss ist. Alles, was hier folgt, gibt es erst seit PHP5. 1. Sichtbarkeit Das bedeutet in diesem Zusammenhang, in wie weit Objekte auf Eigenschaften (Variablen) von Klassen zugreifen und sie verändern können. Oder ob sie die Methoden (Funktionen) von Klassen nutzen oder überschreiben können. Da gibt es drei Möglichkeiten:

• public (kompletter Vollzugriff) • protected (hier können nur die eigene Klasse und die so genannten Kindklassen darauf zugreifen)

• private (hier kann nur innerhalb der Klasse darauf zugriffen werden) Wenn man das alte $var aus PHP 4 nimmt, so wird automatisch public gesetzt. Nehmen wir mal das Beispiel mit "Dieter" und "Dörte". Was sollte er als Erstes tun, um mit seiner Angebeteten zu dinieren? Er muss sie fragen, ob sie dazu bereit ist. Also benötigen wir ein Objekt namens "Telefon", das über die Eigenschaft "klingeln" sowie die Methoden "anrufen" und "telefonieren" verfügt. Damit das nun von anderen Objekten (hauptsächlich weiblichen) genutzt werden kann, muss man einen Vollzugriff erlauben, also: class Telefon { public $klingeln; public function anrufen ($telefonnummer) { ... } public function telefonieren ($anrufer, $angerufener) { ... } } Damit aber die Klasse Telefon nun anrufen und telefonieren ausführen kann, benötigt sie weitere Methoden und Eigenschaften. Also zum Beispiel eine Eigenschaft, in der die Art der Verbindung festgelegt wird, D1, D2, Festnetz und was weiß ich nicht. Dann könnte es noch Methoden geben, die die technische Kommunikation zwischen beiden Personen regeln, also diese Sachen mit den Drähten und den Schaltern. All diese Dinge sind aber unseren beiden Turteltäubchen völlig schnuppe. Die interessiert die Art, wie es abläuft und den Typ der Verbindung nicht (außer später bei der Telefonrechnung). In diesem Fall werden die entsprechenden Eigenschaften und Methoden als private deklariert. class Telefon { public $klingeln; public function anrufen ($telefonnummer) { ... }


public function telefonieren ($anrufer, $angerufener) { ... } private $verbindung; private function kommunikation() { ... } }

2. Sinn und Zweck Wozu denn nun dieses ganze Buhei? Ist es nicht einfacher, einen kompletten Vollzugriff zu erlauben, um flexibler zu sein? Nein. private heißt nicht so etwas wie "das geht dich einen Sch***dreck an", sondern es bedeutet "das ist etwas, um das du dich nicht kümmern musst". Wenn eine Eigenschaft oder Methode ausschließlich für die interne Verarbeitung einer Klasse gedacht ist, so kann das den Benutzern(!) dieser Klasse egal sein. Das hat den Vorteil, dann wenn diese Klasse umprogrammiert wird, der Nutzer seinen(!) Code nicht anpassen muss. Die Klasse Mensch Hier müssen wir natürlich alle Methoden auf public setzen, damit die Objekte über die Methoden die Eigenschaften ändern können. Bei den Eigenschaften ist das in diesem Fall nicht nötig. class Mensch { private $geschlecht; private $namen; public function setGeschlecht($wert) { $this -> geschlecht = $wert; } public function setNamen ($wert) { $this -> namen = $wert; } }

3. protected Um nun zu wissen, wann man mit protected arbeitet, muss man erst etwas über das Vererbungsprinzip wissen.


OOP mit PHP5 - Grundlagen - Vererbung 1. Vererbung Was macht man aber, wenn ein Objekt über zwei Klassen definiert werden muss? Dafür gibt es dann das Konzept der Vererbung, wo Eigenschaften und Methoden auf andere Klassen, den Kindklassen, vererbt werden können. Greifen wir auf unser Beispiel zurück. Dieter ist auf der Suche nach einer besonders guten Gaststätte in seiner Nähe. Also ruft er den regional sehr bekannte Restaurantkritiker Willi Kaluppke aus Castrop-Rauxel an. Das mit der Klasse Mensch ignorieren wir mal. Beide Beteiligten benötigen die Klasse Telefon. Trotzdem ist klar, dass der Nörgelkopp aus dem Ruhrpott sich von Dieter durch spezielles Knowhow und besondere Fähigkeiten unterscheidet. Und dafür brauchen wir eine weitere Klasse. 2. Mutter- und Kindklassen In PHP gibt es das Konzept der EINFACHEN Vererbung. Das heißt, dass eine(!) Mutterklasse ihre Eigenschaften und Methoden auf beliebig viele Kindklassen vererben kann. Allerdings kann eine Kindklasse NICHT die Methoden und Eigenschaften von MEHREREN Elternklassen erben. Konzentrieren wir und jetzt nur auf Willi Kaluppke. Der muss telefonieren und kritisieren können. Das kann man sich so vorstellen. class Telefon { protected function telefonieren ($anrufer, $angerufener) { ... } } class Restaurantkritiker extends Telefon { private $geschmack = true; public function essen_testen ($essen) { ... } public function essen_bewerten ($bewertung) { ... } } Ist ein zugegebenermaßen dummes und unglückliches Beispiel, da Objekte in einer "Istvon"-Beziehung stehen sollten und nicht "Hat-von". Sobald mir was Besseres einfällt, werde ich das hier ändern. extends Damit haben wir nun der Kindklasse Restaurantkritiker die Methoden und Eigenschaften der Elternklasse Telefon vererbt. Aus didaktischen Gründen habe ich diese mal als protected definiert. Das bedeutet, dass nur die eigene Klasse und die Kindklassen(!) darauf zugreifen können. Ist eigentlich ziemlich sinnfrei, da in diesem Fall nur Restaurantkritiker telefonieren können. Um nun aber zum Beispiel auch "Dieter" und "Dörte" das Telefonieren zu ermöglichen, könnte man so vorgehen:


class Mensch extends Telefon { ... }

protected verhindert also in beiden Fällen, dass nicht(!) autorisierte Objekte die Methode telefonieren der Klasse Telefon nutzen können. Das dürfen nur die aus den entsprechenden Kindklassen. 3. Großeltern- und Enkelklassen Jetzt werden natürlich alles Restaurantkritiker einwenden, dass auch sie Menschen sind. Um diesem Einwand zu genügen, könnte man so vorgehen: class Restaurantkritiker extends Mensch { ... } In diesem Fall vererbt die Mutterklasse Telefon die Methode telefonieren an die Kindklasse Mensch. Und die vererbt sie dann weiter an deren(!) Kindklasse Restaurantkritiker. Allerdings gibt es ein Problem! protected lässt nur einen Zugriff der eigentlichen Kindklasse zu, in diesem Fall also Mensch. Damit auch die "Enkelklasse" Restaurantkritiker die Methode telefonieren der "Großelternklasse" nutzen kann, muss diese auf public gesetzt werden, also; class Telefon { ... public function telefonieren (...) { ... } }

3. Erzeugen des Objektes $kaluppke $kaluppke $kaluppke $kaluppke $kaluppke $kaluppke

= new Restaurantkritiker; -> setGeschlecht('männlich'); -> setNamen('Willi'); -> essen_testen('Currywurst, Pommes'); -> essen_bewerten('kotz, spei, würg'); -> telefonieren('Willi',$irgendwer);

Man sieht an diesem (nicht funktionsfähigen) Beispiel, wie Vererbung funktioniert. Das Objekt $kaluppke wird aus der Klasse Restaurantkritiker erzeugt und hat durch extends Zugriff auf die Klasse Mensch. Die wiederum kann auf die Methode telefonieren der Klasse Telefon zugreifen. Wer es nicht so ganz begriffen hat, sollte einfach weiter lesen und sich dann auf das dritte Anfängertutorial stürzen.


OOP mit PHP5 - Grundlagen - Konstruktor und Destruktor 1. Erklärung Hierbei handelt es sich um Methoden, die man auch mit "erzeugen" und "zerstören" beschreiben kann. Also in etwa vergleichbar mit den beiden männlichen Urtrieben "TÖÖÖÖTEN" und "VERMEEEEHREN". Und wie bei Männern auch, erfolgt dies völlig automatisch, ohne dass irgendwas getan werden muss. Scherz beiseite, wir sind ja nicht zum Vergnügen hier. 2. Konstruktor Dies ist die "erzeugen"- bzw. "VERMEEEHREN"-Methode. Sie wird mit __construct aufgerufen. Also bitte ZWEI Unterstriche am Anfang. Wenn man nun aus einer Klasse ein Objekt erzeugt, so wird diesem durch den Konstruktor schon etwas in die Wiege gelegt. Man kann also schon vor der eigentlichen Verwendung etwas festlegen. Das klassische Beispiel wäre eine MySQL-Klasse. class MySQL { private $db; public function __construct ($host, $user, $password) { $this -> db = mysql_connect ($host, $user, $password) } } So würde schon bei der Erzeugung des Objektes "MySQL" automatisch eine Verbindung zur Datenbank aufgebaut. $mysql = new MySQL ($host, $user, $password);

3. Destruktor Dies ist die "zerstören"- bzw. "TÖÖÖÖTEN"-Methode. Sobald alle Verweise auf ein Objekt entfernt wurden, wird Selbiges automatisch "geplättet", das heißt vernichtet. Sollte also zum Beispiel keine Referenz mehr auf die Verbindung zu einer Datenbank verweisen, so wird diese getrennt. public function __destruct () { mysql_close ($this -> db); }

4. Rückgabewerte Leider gibt es bei diesem Methoden keine. Wie kann man dann überprüfen, ob sie funktionieren? Da gibt es mehrere Möglichkeiten. Man könnte bei SQL-Abfragen eine dieAnweisung im Falle eines Fehlers einbauen. Möglich wäre auch eine try-catch-Anweisung, zu der ich später komme. Oder man betet einfach. Keine Angst, beim entsprechenden Tutorial werde ich darauf eingehen. 5. Konstruktormethoden in Elternklassen Beinhaltet eine Elternklasse ebenfalls ein __construct oder __destruct, so werden diese NICHT automatisch aufgerufen, sondern müssen initialisert werden. Das gibt es aber eine


spezielle Methodik, die ich sp채ter erl채utern werde. Ausnahme, die Kindklasse verf체gt nicht 체ber einen eigenen Konstruktor.


OOP mit PHP5 - Grundlagen - Paamayim Nekudotayim 1. #*#?+|~°^* ????? Paamayim Nekudotayim? Hat der Kerl gesoffen, oder sich auf der Tastatur abgestützt? Oder steht er kurz vor dem Eintritt ins Nirvana? Keine Angst, ich stehe auch nicht unter dem Einfluss von illegalen Halluzinogenen. Ich habe nur das PHP-Handbuch gelesen. Paamayim Nekudotayim ist hebräisch, bedeutet Doppel-Doppelpunkt und wurde von der Firma Zend als Benamung für den so genannten Gültigkeitsoperator auserkoren. Der kommt immer dann zum Einsatz, wenn man sich außerhalb des Objektkontextes bewegt. Also beim Zugriff auf statische Variablen und Methoden, Konstanten und abstrakte Methoden (dazu später mehr). Extrem wichtig ist hier die Sichtbarkeit. 2. Zugriff innerhalb von Klassen In der eigenen Klasse Geschieht dies mit self::. class Mensch { protected static $bock; public function setBereitschaft ($wert) { self::$bock = $wert; } } class Lohnsteuerjahresausgleich { const MWST = 0.19; public function returnMWST () { return self::MWST; } } In der Elternklasse Hierfür benötigt man parent::. Ist englisch, heißt Eltern, und klingt somit auch logisch. Ich habe zum Beispiel beim Abschnitt Konstruktor und Destruktor darauf hingewiesen, dass diese bei der Implementierung in eine Kindklasse nicht automatisch aufgerufen werden. Das könnte man so machen: class Mutter { public function __construct() { ... // irgendwas } }


class Rotzblag extends Mutter { public function __construct() { // Ruft Konstruktor von Mutter auf parent::__construct(); } } $blag = new Rotzblag(); Ein Zugriff auf Konstanten in der Elternklasse sähe dann so aus: class Lohnsteuerjahresausgleich { const MWST = 0.19; } class Mensch extends Lohnsteuerjahresausgleich { public function getMWST () { echo parent::MWST; } } $dieter = new Mensch; $dieter -> getMWST();

3. Zugriff außerhalb von Klassen Dies ist nur möglich bei Konstanten, als public definierten statischen Variablen sowie abstrakten und statischen Methoden (dazu komme ich gleich). Dazu reicht ein [Klassenname]::[Variable/Methode]aus. class Mensch { public static $bock; public static function setBereitschaft ($wert) { self::$bock = $wert; } } Mensch::setBereitschaft('kein Bock'); echo Mensch::$bock;


OOP mit PHP5 - Grundlagen - Typprüfung 1. Instanceof Mit instanceof kann man überprüfen, ob ein Objekt von einer bestimmten Klasse abgeleitet worden ist. Greifen wir dazu wieder mal auf unsere beiden Hauptakteure zurück. Ein einfaches Beispiel könnte so aussehen: class Sex { public function beischlaf ($er, $sie) { ... } } class Mann { ... } class Frau { ... } $dieter = new Mann; $doerte = new Frau; if ($dieter instanceof Mann && $doerte instanceof Frau) { $sex = new Sex; $sex -> beischlaf ($dieter, $doerte); } In diesem Beispiel verhindern wir, dass Dieter nach einem feuchtfröhlichen Abend nicht am nächsten Morgen neben einem behaarten Männerhintern aufwacht. Man kann auch direkt in den Methoden entsprechende Überprüfungen vornehmen, aber dazu komme ich später bei den Tutorials. 2. Type Hinting Bei dieser Art hat man neben den Objekten noch die zusätzliche Möglichkeit, auf Arrays hin zu prüfen. Integer und String, wie in anderen Sprachen möglich, sind derzeit noch nicht eingebaut. Hoffentlich kommt das in der nächsten Version. Objekte Anstelle von instanceof kann man die Bindung von Objekten an bestimmte Klassen auch so festlegen:


class Sex { public function beischlaf (Mann $er, Frau $sie) { ... } } class Mann { ... } class Frau { ... } $dieter = new Mann; $doerte = new Frau; $sex = new Sex; $sex -> beischlaf ($dieter, $doerte); Mit public function beischlaf (Mann $er, Frau $sie) legt man fest, dass die Objekte aus den entsprechenden Klassen hergeleitet sein mĂźssen, also $er aus der Klasse Mann und $sie aus der Klasse Frau. Arrays (seit PHP 5.1) Hier ist die Sache ganz einfach. Der Parameter einer Methode muss ein Array sein. Das kĂśnnte so aussehen: class Sex { public function beischlaf (Mann $er, Frau $sie, array $verhuetungsmittel) { ... } } class Mann { } class Frau { } $dieter = new Mann; $doerte = new Frau; $sex = new Sex; $sex -> beischlaf ($dieter, $doerte, array ('kondom', 'pille')); Sicher ist sicher!


Erläuterung Sowohl bei instanceof als auch beim Type Hinting wird KEINE Überprüfung der WERTE vorgenommen! Entscheidend ist nur, dass eine Bedingung erfüllt ist, also dass Parameter Objekte einer Klasse sind oder zusätzlich Arrays beim Type Hinting.


OOP mit PHP5 - Fortgeschrittenes - Statische Methoden und Eigenschaften 1. Statische Eigenschaften (statische Variablen/Member oder Klassenvariablen) Sind besonders dann interessant, wenn zwei Objekte miteinander agieren müssen, und man eine gemeinsame Basis dafür festlegen will. Kommen wir zu unseren beiden Protagonisten zurück. Damit die sich zu einem Abendessen treffen, muss bei beiden die Bereitschaft dazu vorhanden sein. Wenn bloß einer nicht will, kann man die ganze Sache vergessen. Das WICHTIGE bei den so genannten statischen Variablen ist, dass sie sich außerhalb des eigentlichen Objektkontextes bewegen. Soll heißen, wenn zum Beispiel ein Objekt sie ändert, so geschieht dies global, also bei allen anderen Objekten auch! class Mensch { ... protected static $bock; public function setBereitschaft ($wert) { self::$bock = $wert; } public function returnBereitschaft () { return self::$bock; } } $dieter = new Mensch; $dieter -> setBereitschaft('jau'); $doerte = new Mensch; $doerte -> setBereitschaft('kein Bock'); $bereitschaft = $dieter -> returnBereitschaft (); //Ergibt 'kein Bock', dank Dörtes Unlust echo $bereitschaft; Erläuterung Eine statische Variable wird mit static festgelegt. Um innerhalb der Klasse mit einer Methode den Wert zu ändern, greift man mit self:: darauf zu. Ein $this -> bock führt zu einer Fehlermeldung, da statische Variablen nicht an Objekte gebunden sind. Zum Aufruf außerhalb von Objekten komme ich nun, da es in obigem Beispiel nicht funktioniert. Dort haben wir $bock als protected eingestuft. Damit verhindern wir, dass Kreti und Pleti den Wert ändern können. Das ist nur den Objekten aus der Klasse Mensch und den Kindklassen vorbehalten. public static In diesem Fall kann der Wert der Eigenschaft wirklich von jedem und überall geändert werden. Bei dieser Doppelpunkt-Sache (das mit dem komischen Namen) habe ich euch das schon gezeigt. Es ginge auch so: Mensch::$bock = 'irgendwas';


2. Statische Methoden Bei denen gilt das Selbe wie bei statischen Eigenschaften. Allerdings ist die Handhabung anders, besonders bei der unterschiedlichen Sichtbarkeit. public Hier kann man außerhalb des Objektkontextes jederzeit die Methoden aufrufen. Ein Beispiel könnte so aussehen. Wenn Dörte "kein Bock" auf Dieter hat, ist alles Weitere sinnlos. Also könnte man eine entsprechende Methode einbauen, die die weitere Verarbeitung beendet: class Mensch { public static $bock; ... public static function finito() { header ('Location: http://www.singleboerse.de'); } } if (Mensch::$bock == 'kein Bock') { Mensch::finito(); } private Bei oben beschriebener Vorgehensweise könnte allerdings leicht ein böser Zeitgenosse (oder schlampiger Programmierer) einfach so was einbauen: Mensch::finito(); Indem man $bock als private deklariert, erhöht man die Sicherheitsstufe. So kann nur noch die Klasse Mensch selber Einfluss nehmen: class Mensch { private static $bock; public function setBereitschaft ($wert) { self::$bock = $wert; if (self::$bock == 'kein Bock') { self::finito(); } } private static function finito() { header ('Location: http://www.singleboerse.de'); } } $dieter = new Mensch; $dieter -> setBereitschaft('jau'); $doerte = new Mensch; $doerte -> setBereitschaft('kein Bock');


protected Sobald mir hierzu ein vern체nftiges Beispiel einf채llt, tue ich es euch kund. Bis dahin m체sst ihr warten.


OOP mit PHP5 - Fortgeschrittenes - Schnittstellen 1. Erklärung Schnittstellen, die auch INTERFACES genannt werden, sind eine elegante Möglichkeit festzulegen, über welche Methoden eine Klasse verfügen muss. Dabei ist es diesen Interfaces völlig schnuppe, wie diese Methoden aussehen. Man gibt einfach etwas vor. Wenn es die Klasse nicht erfüllt, dann ist "hängen im Schacht", vulgo, es wird eine Fehlermeldung ausgegeben. Kommen wir wieder zu "Dieter" und "Dörte" zurück. Also bevor sie sich mit einem Kerl verabredet, erwartet sie, dass der ein paar Dinge beherrscht. Gut, bei Frauen ist diese Liste meist recht lang, wir konzentrieren uns aber nur auf zwei. Er sollte erstens zumindest die elementaren Grundregeln des guten Benehmens beherrschen und zweitens ihr Blumen mitbringen. 2. Das Interface Eine Schnittstelle wird, wie unten zu sehen, mit dem Schlüsselwort interface definiert. Darin legt man die Methoden fest, über die eine Klasse verfügen muss, um die Schnittstelle zu nutzen. interface Traummann { public function benehmen($tuer_aufhalt, $dame_zuerst); public function blumen_mitbring($blumen); }

3. Die Einbindung in eine Klasse Dies geschieht mit der Anweisung implements. Damit wird die entsprechende Schnittstelle in die Klasse eingebunden. class Mann implements Traummann { public function benehmen($tuer_aufhalt, $dame_zuerst) { ... } public function blumen_mitbring($blumen) { ... } private function sei_wie_du_bist($arschkratz, $ruelps) { ... } }

4. Der Sinn Nehmen wir mal an, dass die Klasse "Mann" von eben einem solchen programmiert worden ist. In diesem Fall handelt es sich um einen richtigen Chauvinisten, der Frauen als "Mann 0.1 Beta" einstuft. Woher soll der nun wissen, dass bestimmte Methoden erwartet werden, um sich mit einem Objekt der Klasse "Frau" zu verabreden. Nun, das erklärt ihm dann eine Frau, die die Schnittstelle Traummann entwickelt und sagt: "Die musst du nutzen, sonst geht gar nichts". So kann man sich in etwa die Funktionsweise von Interfaces vorstellen.


5. Einbindung von mehreren Interfaces Jetzt könnte unser oben beschriebener Neandertaler auch einen Kollegen haben, der ihm weitere Informationen liefern kann, damit sich Dörte mit Dieter verabredet. Zum Beispiel die Grundbegriffe der Hygiene: interface Hygiene { public function rasieren($rasierer); public function duschen($duschgel); public function deo_benutzen($deo); } Um nun mehrere Interfaces zu nutzen, reiht man sie einfach hintereinander, durch ein Komma getrennt: class Mann implements Traummann, Hygiene { ... }

6. Hinweise Methoden Alle Methoden, die in Interfaces eingebaut sind, müssen vom Typ public sein! Das gilt auch für selbige in den entsprechenden Klassen. Ansonsten gibt es eine Fehlermeldung. Wichtig ist auch, dass der Name der Methode identisch ist. Parameter der Methoden Wenn man in einem Interface eine Methode definiert, so muss in der Klasse mindestens die Anzahl der Parameter übereinstimmen. Die Benamung der Variablen selber kann abweichen. Eigenschaften Natürlich würde sich "Dörte" wünschen, dass "Dieter" auch noch sehr attraktiv ist. Das ist aber leider eine Eigenschaft, keine Methode und kann somit in Schnittstellen nicht vorgegeben werden.


OOP mit PHP5 - Fortgeschrittenes - Abstrakte Klassen 1. Definition Eine abstrakte Klasse ist ein Interface mit zusätzlichen Methoden und kann nur von anderen Klassen eingebunden werden. Von ihr selber darf man keine Objekte erzeugen. Verstanden? Nein? OK, ein Beispiel. Unter dem Punkt Schnittstellen hatten wir zum Schluss in zwei Interfaces die Methoden definiert, über die eine Klasse Mann verfügen muss, um sich mit Frauen verabreden zu können. Jetzt gehen wir einfach mal davon aus, dass der Programmierer dieser Klasse ein Frauenversteher ist und sich mit den Prinzipien der Hygiene auskennt. Wann ist eine Klasse abstrakt? Sobald man eine Methode als solches definiert. Die ist dann, einfach ausgedrückt, ein Interface in dieser Klasse. Dies geschieht mit dem Schlüsselwort abstract, das man sowohl für die Methode als auch für die Klasse benutzen muss. 2. Ein Beispiel Also, unser Programmierer entwickelt nun für die Klasse Mann eine Erweiterung in Form einer abstrakten Klasse namens Frauenversteher. Da aber eigentlich jeder Mann die Frauen nie wirklich verstehen wird, ist er ein wenig vorsichtig. Er legt also zwei abstrakte Methoden fest, von denen er weiss, dass sie wohl zum Ziel führen, aber nicht wie. abstract class Frauenversteher { abstract protected function benehmen($tuer_aufhalt); abstract protected function blumen_mitbring($blumen); } Das bedeutet für die Klasse Mann, dass sie entsprechend erweitert werden sollte und dann über dieselben Methoden verfügen muss. class Mann extends Frauenversteher { protected function benehmen($tuer_aufhalt) { ... } protected function blumen_mitbring($blumen) { ... } }

3. Weitere Methoden Im Gegensatz zu den Interfaces kann man bei einer abstrakten Klasse zusätzliche Methoden einbauen. Einfach ausgedrückt bedeutet das Folgendes. Unser Programmierer ist sich bei den oben beschriebenen Methoden nicht so ganz sicher. Er weiß aber ganz genau, dass ein Mann vom Typ "Müffi, das Geruchsgespenst" bei Frauen sofort abblitzt. Also kann er in diesem Fall zusätzliche Methode einbauen, die wir vorher über ein Interface definiert werden mussten.


abstract class Frauenversteher { abstract protected function benehmen($tuer_aufhalt); abstract protected function blumen_mitbring($blumen); protected function rasieren($rasierer) { ... } protected function duschen($duschgel) { ... } }

4. Sichtbarkeit Im Gegensatz zu den Interfaces hat man hier die Möglichkeit unterschiedliche Sichtbarkeiten zu definieren. Allerdings gilt das nur für protected und public, private ist verboten. Dabei kann die Methode in der eigentlichen Klasse eine größere Sichtbarkeit haben, als in der abstrakten Klasse vorgegeben worden ist. abstract class Frauenversteher { abstract protected function benehmen($tuer_aufhalt); } class Mann extends Frauenversteher { public function benehmen($tuer_aufhalt) { ... } }


OOP mit PHP5 - Fortgeschrittenes - Überschreiben 1. Einführung Die Technik, die ich euch nun erläutern werde, ist in anderen Sprachen unter den Begriffen "Überladung / Overloading" bekannt. PHP macht da mal wieder eine Ausnahme. Da versteht man darunter etwas, das zumindest Sebastian Bergmann mit dem Ausdruck "Interzeptormethoden" bezeichnet. Dazu komme ich aber später. Überschreiben bedeutet, dass man in Kindklassen Methoden oder Eigenschaften der Elternklasse anpassen bzw. ändern kann. Ich will das an folgendem etwas sinnfreiem Beispiel erklären (nicht rumnörgeln, immer die richtigen Beispiele für Anfänger zu finden, ist extrem schwer). 2. Das Beispiel Bevor sich Dieter und Dörte zu ihrem ersten Rendez-Vouz treffen, machen sie was? Genau, sie betreiben Körperpflege! Allerdings unterscheidet die sich sehr stark bei den Geschlechtern. Der Basiscode: class Mensch { private $gewaschen; private function koerperpflege ($wert) { $this -> gewaschen = $wert; } public function returnPflege ($wert) { $this -> koerperpflege ($wert); return $this -> gewaschen; } } class Mann extends Mensch { } $dieter = new Mann; echo 'Dieter: <br>Folgendes Körperpflegemittel wurde benutzt: '; $benutzt = $dieter -> returnPflege('Seife'); echo $benutzt; Erläuterung Ist ganz einfach. Die Klasse Mann erbt die Methoden und Eigenschaften der Klasse Mensch. Nun ist es bei Männern so [Ironie], dass sie bei der Körperpflege deutlich weniger Aufwand betreiben als Frauen. In diesem Fall arbeiten wir bei den Pflegemitteln nur mit einem Wert. 3. Überschreiben So, wir gehen jetzt einfach mal davon aus, dass in unserer Programmierung Männer die Hauptrolle spielen und Frauen nur am Rande auftauchen. Das hat zwar mit dem realen Leben nichts zu tun, ist aber im Moment egal. Im Gegensatz zu Männern benutzen Frauen nicht nur einfache Seife, nein, die haben ein rieeeeesiges Sammelsurium von Utensilien. Leider sehen unsere Methoden und


Eigenschaften das nicht vor. Also kann man das für diesen "Ausnahmefall" entsprechend anpassen: class Frau extends Mensch { private $gewaschen = array(); private function koerperpflege ($wert) { foreach ($wert as $value) { $this -> gewaschen[] = $value; } return $this -> gewaschen; } } Erläuterung

$gewaschen wurde in der Klasse Mensch als stinknormale Variable definiert. Da das aber bei Frauen nicht ausreicht, haben wir den Typ in der Klasse Frau als Array festgelegt. Damit "ÜBERSCHREIBEN" wir die Variable aus der Klasse Mensch. Um die aber nun verarbeiten zu können, müssen wir das auch bei der entsprechenden Methode tun. Die Verarbeitung sieht dann so aus: $doerte = new Frau; $benutzt = $doerte -> returnPflege( array ( 'Deo', 'Haarwaschmittel', 'Pflegecreme', 'Hautbalsam')); echo 'Dörte: <br>Folgende Körperpflegemittel wurden benutzt: '; print_r ($benutzt);

4.Sichtbarkeit Die zu überschreibenden Eigenschaften und Methoden müssen mindestens über die selbe Sichtbarkeitstufe verfügen wie das Original. Definiert man zum Beispiel in der Klasse Mensch die Variable $gewaschen als protected, so darf man in der Klasse Frau sie nicht als private deklarieren. In diesem Fall wäre die Sichtbarkeit in der Kindklasse geringer als in der Elternklasse. Dasselbe gilt natürlich auch für die Methoden. 5. Einsatzmöglichkeiten In was für Situationen sollte man nun etwas überschreiben? Meine Meinung dazu ist: in Ausnahmefällen! Je häufiger man auf diese Technik zurückgreift, desto schlechter ist das Konzept der Anwendung.


OOP mit PHP5 - Fortgeschrittenes - Finale Klassen und Methoden 1. Nix überschreiben Wie aber kann man verhindern, dass Eigenschaften und Methoden überschrieben werden können? Nun dafür gibt es das Schlüsselwort final. Damit kann man verhindern, dass obiges geschieht. Allerdings gibt es einen gewaltigen Unterschied bei den Methoden und Eigenschaften. 2. Eigenschaften Leider ist es nicht möglich, gezielt einzelne Eigenschaften als final zu deklarieren. Es ist, genau gesagt, überhaupt nicht möglich! Um zu verhindern, dass Eigenschaften NICHT überschrieben werden können, gibt es nur eine radikale Methode. Man definiert die Klasse als final. final class Mensch { ... } Leider hat das zur Folge, dass diese nicht mehr als Elternklasse zur Verfügung steht. Das heißt, sie kann nicht über extends in Kindklassen eingebunden werden. final class Mensch { ... } class Mann extends Mensch { ... } erzeugt eine Fehlermeldung à la Class Mann may not inherit from final class (Mensch) in.... Also fassen wir zusammen. Es gibt KEINE finalen Eigenschaften sondern nur FINALE KLASSEN. 3.Methoden Hier sieht es gottlob deutlich besser aus. Man kann tatsächlich einzelne Methoden mit final vor dem Überschreiben schützen. Nehmen wir unser Beispiel aus dem Kapitel Überschreiben. Jetzt gehen wir mal davon aus, dass der große Obermufti (leitender ChefEntwickler) der Meinung ist, dass es für den weiteren Verlauf der Programmierung völlig unerheblich ist, die jeweilige Art der Körperpflege zu kennen. Also wird die Methode koerperpflege als final festgelegt. Damit verhindert man zum einen, dass sie überschrieben werden kann, lässt aber andererseits zu, dass Mensch weiterhin als Elternklasse zur Verfügung steht. class Mensch { final private function koerperpflege ($wert) { ... } }


class Frau extends Mensch { private function koerperpflege ($wert) { ... } } Hier bekommt ihr ebenfalls eine Fehlermeldung im Stile von Cannot override final

method Mensch::koerperpflege() in ...,wobei class Mensch { final private function koerperpflege ($wert) { ... } } class Frau extends Mensch { ... } tadellos funktioniert, solange man in der Klasse Frau nicht versucht, die Methode koerperpflege zu 端berschreiben.


OOP mit PHP5 - Fortgeschrittenes - Autoload 1. Erklärung Diese Methode wird automatisch aufgerufen, wenn mittels new ein Objekt aus einer Klasse erzeugt werden soll, letztere aber zu diesem Zeitpunkt noch nicht vorhanden ist. Dabei wird als einziger Parameter der Name besagter Klasse gesetzt. Allerdings ist diese Methode nicht an Klassen gebunden, sondern wird ganz normal innerhalb des Quellcodes aufgerufen. Und wann kann man das einsetzen? Ganz einfach. In der Objektorientierten Programmierung ist zum Beispiel folgender Grundsatz sehr weit verbreitet. "Jede Klasse wird in einer eigenen Datei abgespeichert" [Quelle: weit verbreiteter Grundsatz] Damit soll gewährleistet sein, dass einmal programmierte Klassen so oft wie möglich wieder verwendet werden können. 2. Das Beispiel Daraus ergibt sich ein Problem. Man müsste jedes Mal alle Klassen über require oder include einbinden, was zu einer waren Sysiphusarbeit ausarten kann. Stattdessen arbeitet man mit __autoload. Nehmen wir mal unser altes Beispiel mit Dieter und Dörte, allerdings in extrem verkürzter Form. // Mensch.php class Mensch {...} // Mann.php class Mann extends Mensch {...} // Frau.php class Frau extends Mensch {...} // bla.php function __autoload($class) { require 'class/'.$class.'.php'; } $dieter = new Mann; $doerte = new Frau; In diesem Fall werden alle benötigten Klassendateien automatisch über require eingebunden. Vorausgesetzt, dass die Dateinamen identisch sind mit den Klassenamen und in einem Ordner namens class liegen! Also achtet auf die Groß- und Kleinschreibung. Erstaunlicherweise wird sogar die Mensch.php eingebunden, da sie über extends in die beiden anderen Klassen "integriert" ist. 3. Probleme Neben einer einheitlichen Benamung der Klassen und Dateien gibt es noch andere Schwierigkeiten. Sollte die entsprechende Datei nicht gefunden werden, so verabschiedet sich PHP mit einem Fatal error. Leider kann man das nicht mit der üblichen Fehlerbehandlung abfangen. Selbst mit try ... catch lässt sich dieses Problem nicht umgehen. Man muss in diesem Fall ein klein wenig pfuschen, mit dem üblen eval und class_exists. Da Letzteres später kommt, verzichte ich im Moment darauf.


OOP mit PHP5 - Fortgeschrittenes - Iteratoren In PHP5 kann man mit foreach die Eigenschaften einer Klasse mit samt Ihren Werten auslesen. Dabei gibt einen kleinen aber feinen Unterschied. Greift man außerhalb der Klasse zu, so werden nur die als public deklarierten Eigenschaften zurückgegeben, innerhalb der Klasse dagegen alle. class MyClass { public $blubb = 'blubber'; public $schwall = 'laber'; public $jodelblah = 'Hollahihü'; protected $finger_wech = 'geht dich nichts an'; private $nee_is_nich = 'das hier auch nicht'; function iterateVisible() { foreach($this as $key => $value) { print $key.'-'.$value.'<br>'; } } } $vars = new MyClass(); foreach ($vars as $key => $value) { echo $key.'-'.$value.'<br>'; } echo '-----------------<br>'; $vars -> iterateVisible(); Leider hat man hier nur die Möglichkeit zwischen Allem oder Nichts. Was aber macht man, wenn man zum Beispiel den Zugriff nur auf ganz bestimmte Eigenschaften, zum Beispiel einem Array, zulassen möchte? 2. Die Lösung In PHP5 ist bereits ein Interface names Iterator eingebaut, mit dem man die Zugriffe steuert. Dazu benötigt man fünf Methoden:

• rewind (setzt den Zeiger auf den Anfang zurück) • current (gibt den aktuellen Wert zurück) • next (setzt den Zeiger um Einen nach vorn) • key (gibt den aktuellen Index zurück) • valid (prüft,ob nach rewind oder next noch ein Element da ist) Ein Beispiel Kommen wir mal zu Dörte bzw. den Frauen im Allgemeinen zurück. Da gibt es Vieles, was wir Männer brennend gerne in Erfahrung brächten. Was haben die in ihren Handtaschen oder was sind deren geheimste Träume. Jetzt sagt aber der Programmierer (besser die Programmiererin), dass uns die geheimsten Träume einen feuchten Kehricht angehen, ein Blick in die Handtasche aber erlaubt ist. Dafür benötigt man nur Folgendes:


class Frau implements Iterator { private $handtascheninhalt = array( 'a' => 'Lippenstift', 'b' => 'Taschent체cher', 'c' => 'Pfefferspray' ); private $geheime_traeume = array('XXXXX','YYYYY','ZZZZZ'); public function rewind() { reset ($this -> handtascheninhalt); } public function next() { return next($this -> handtascheninhalt); } public function current() { return current($this -> handtascheninhalt); } public function key() { return key ($this -> handtascheninhalt); } public function valid() { return $this -> current() !== false; } } $frau = new Frau; foreach ($frau as $key => $value) { print "$key: $value<br>"; } Hier wird tats채chlich nur der Inhalt der Handtasche preisgegeben und nicht die geheimsten Tr채ume der der Frauen. Eigentlich schade! Man kann das noch verfeinern, aber darauf gehe ich sp채ter in den Tutorials ein.


OOP mit PHP5 - Fehlerbehandlung 1. Das Tutorial Ich hoffe, dass ihr euch alle schon mein Tutorial zum Thema "Fehlersuche" zu Gemüte geführt habt. Denn wenn ihr nicht mit den elementaren Prinzipien vertraut seid, bringt das hier gar nichts. 2. Fehler Wie ihr Alle nun schon wisst, gibt es einfach gesagt, vier Formen von Fehlern, die vom PHPInterpreter bei den entsprechenden Error-Leveln ausgegeben werden. Zur Erinnerung noch mal kurz die Liste:

• Fatal errors • Parse errors • Warnings • Notices Error-Reporting Um nun vernünftig objektorientiert zu programmieren, reicht ein E_ALL nicht mehr aus. Um Unsauberkeiten im Code zu erkennen, sollte man sich tunlichst für diese Variante entscheiden: error_reporting (E_ALL | E_STRICT). Da werden nicht nur "echte" Fehler gemeldet, nein, ihr bekommt auch noch Hinweise auf schlampigen Code. Und im Gegensatz zur prozeduralen Programmierung sind bei der OOP diese Meldungen sehr wichtig! Warum E_ALL | E_STRICT? Unter dem Punkt Wozu OOP? habe ich bei den Vorteilen darauf hingewiesen, dass diese eine saubere Programmierung voraussetzen. Nur leider ist es so, dass wirklich wichtige Hinweise bei der OOP nur unter E_STRICT ausgegeben werden. Und glaubt mir, ohne diese Einstellung sucht ihr euch einen Wolf, wenn ihr wissen wollt, warum bestimmte Dinge nicht funktionieren. Und glaubt mir, ich rede hier aus eigener Erfahrung. Daher ist diese Einstellung auf meinem Linux-Server zu Hause mittlerweile Standard. In der Firma habe ich mit zu vielen Altlasten zu kämpfen, da wäre das nicht praktikabel. 3. Viele Köche verderben den Brei Das sind wahrlich wahre Worte. Leider sieht der Alltag von vielen Programmierern anders aus. Da werkeln dann fünf, zehn, zwanzig oder noch mehr arme Menschen an einer Anwendung herum. Wie soll man da den Überblick behalten, wenn Kollege "X" eine Klasse entwirft, die über Interfaces oder abstrakte Klassen von Kollege "Y" vorgegeben wurde, und dann ein Ergebnis zurückzuliefern, das Kollege "Z" in einem bestimmten Format benötigt? Logik Um denn nun Ordnung in dieses Chaos zu bringen, gibt es in PHP5 endlich eine Möglichkeit, Ausnahmen abzufangen. Dabei kann man selber Fehlermeldungen oder -codes erzeugen und diese entsprechend abfangen, inklusive Ablaufverfolgung, Angaben über die Datei oder die Codezeile. 4. Der einsame Wolf Die Einzelkämpfer unter euch werden jetzt sicher einwenden, dass sie so was nicht brauchen, da sie eh nur alleine an Etwas programmieren und ihren Code kennen. Stimmt, aber was ist in einem Jahr. Kennt ihr den dann immer noch? Auch die Coder-Singles unter euch sollten diese neuen Möglichkeiten nutzen.


OOP mit PHP5 - Fehlerbehandlung - Exceptions 1. Exception In PHP5 wurde direkt eine Klasse namens Exception eingebaut, mit der man in Ausnahmen festlegen und verarbeiten kann. Damit ist es möglich, logische(!) Fehler innerhalb des eigenen Codes abzufangen. Diese vorgegebene Klasse verfügt über die folgenden Eigenschaften und Methoden:

• Eigenschaften o message (string) = Fehlermeldung o code (int) = Fehlercode o file (string) = Datei mit Fehler o line (int) = Zeilennummer des Fehlers o trace (array) = für eine Ablaufverfolgung o string (string) = Formatierter String der Ablaufverfolgung • Methoden o __construct ($message = null, $code = 0) = "VERMEEHREN"-Methode o getCode() = liefert den Fehlercode o getFile() = liefert die Datei mit dem Fehler o getLine() = liefert die Zeilennummer o getMessage() = liefert die Fehlermeldung o getTrace() = liefert ein Array der Ablaufverfolgung o getTraceAsString() = liefert einen formatierten String der Ablaufverfolgung Diese Klasse ist direkt in PHP implementiert und kann nicht selber in den eigenen Code eingebaut werden. 2. Benutzung Man kann nun diese Klasse direkt über extends direkt in andere "einbauen". Also so was wie class Mensch extends Exception. Dann besteht noch die Möglichkeit, zwischen verschiedenen Ausnahmen zu unterscheiden. Es gibt dann zum Beispiel die echt brutalen Böcke, die man schießen kann, oder harmlose Unfälle, die nicht ganz so schlimm sind. 3. Ein Beispiel Dieter hat denn nun ein Taxi bestellt, um mit seiner Dörte in ein Restaurant zu fahren. Nehmen wir jetzt mal zwei Fälle an, die den weiteren Verlauf des Abends beeinflussen können, einen schwerwiegenden und einen nicht so schlimmen. Der schwerwiegende Fall Der Taxifahrer fährt wie eine gesengte Sau und baut einen so schweren Unfall, dass unsere beiden Turteltauben schwer verletzt im Krankenhaus landen. In diesem Fall wollen wir eine passende Ausnahmebehandlung definieren class unfallexception extends exception {} Der nicht so schlimme Fall Beim Essen geht einiges schief. Der Fresstempel ist eine Katastrophe, weil unser Programmierer die Klasse Restaurantkritiker nicht sauber umgesetzt hat. Oder Dieter kippt vor lauter Aufregung Rotwein auf das neue und sündhafte teure Kleid von Dörte. class essenexception extends exception {} Und wie man jetzt mit diesen Exceptions arbeitet, erfahrt ihr nun.


OOP mit PHP5 - Fehlerbehandlung - Ausnahmen 1. Versuchen, fangen, schmeißen Mit diesen drei Begriffen kann man die Fehlerbehandlung in PHP5 beschreiben. Als Erstes versucht man etwas (try), wenn das misslingt, fängt (catch) man das ab, um dann mit den Meldungen um sich zu schmeißen (throw). Und dem entsprechend sieht das dann so aus: class fehlermeldung extends Exception {} try { tuWas(); } catch (Exception $ausnahme_1) { // 1. Ausnahme ... } catch (Exception $ausnahme_2) { // 2. Ausnahme ... }

2. Ausnahmebehandlung Bei den Interfaces und Methoden hatten wir schon mal ein Beispiel, wo unser Objekt "Dieter" über ein paar Methoden verfügen sollte, damit er es sich bei "Dörte" nicht verscherzt. Dazu gehörte auch das "Blumen mitbringen". Allerdings nicht nur eine, sondern ganz viele. Eine entsprechende Ausnahmebehandlung könnte dann so aussehen: class frauenexception extends Exception {} class Traumman { public function blumen_mitbring($blumen) { if (!is_array ($blumen) || count ($blumen) < 20) { throw new frauenexception ( 'Ich wollte viele Blumen, nicht nur eine, du Geizhalz', 10); } else { $treffer = 'Ins Schwarze. Das geht heute noch was'; return $treffer; } } } $dieter = new Trauman;


try { $erfolg_bei_frauen = $dieter -> blumen_mitbring ('Tulpe'); echo $erfolg_bei_frauen; } catch (frauenexception $exception) { echo 'Code: '.$exception -> getCode().'<br>'; echo 'Fehler: '.$exception -> getMessage().'<br>'; echo 'Datei: '.$exception -> getFile().'<br>'; echo 'Zeile: '.$exception -> getLine().'<br>'; } Erläuterung Mit class frauenexception extends Exception {} erzeugen wir eine "leere" Klasse für die Ausnahmebehandlung bei Frauenwünschen. In der Klasse Traumman sagen wir dann in der Methode blumen_mitbring, dass es schon ein ordentlicher Strauß sein sollte, also ein Array mit mindestens 20 Werten (Blumen). Wenn dem nicht so ist, wird eine entsprechende Meldung mit samt eines "Fehlercodes", also der Zahl 10, ausgegeben. Der wird allerdings willkürlich definiert, also zum Beispiel vom Projektmanager vorgegeben. In diesem Fall müsste der Entwickler in einem Handbuch nachschauen, um herauszufinden, dass der Parameter $blumen ein Array mit mindestens 20 Werten sein muss. Anschließend erzeugen wir unser Objekt "Dieter" und versuchen (try) uns an der Methode blumen_mitbring. Leider schlägt das fehl, da unser Dieter nur mit einer dämlichen Tulpe anrückt. Also fangen (catch) wir das ab, indem wir mit ein paar Standardmethoden der Exception-Klasse(!) uns die entsprechenden Hinweise ausgeben lassen. catch (frauenxception $exception) ... $exception -> get... Mit diesem Konstrukt erzeugt man ein "Ausnahme"-Objekt aus der "leeren" Klasse frauenxception. Damit erst hat man direkten Zugriff auf die Eigenschaften uns Methoden der Exception-Klasse (eingebunden über class frauenxception extends Exception). 3. Fazit Dies ist nur ein erster Einblick in die Ausnahmebehandlung. Tatsächlich sind die Möglichkeiten viel komplexer, als ich hier beschrieben habe. Beim Anfängertutorial 2 werdet ihr dann mit der Praxis konfrontiert.


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.