Objektorientierte Programmierung, Entwurfsmuster und guter Programmierstil mit PHP

OOP – Objektorientierung in PHP

PHP ist (nicht) objektorientiert

… aber es bietet die Möglichkeit objektorientiert zu programmieren. PHP besteht hauptsächlich aus Elementen der prozeduralen Programmierung. Ein ganze Menge Funktionen aber nur wenige Klassen werden von PHP bereitgestellt. Datentypen sind keine Objekte sondern Literale. Seit PHP 5 ist es aber so, dass man ganz hervorragend objektorienterte Programme umsetzen kann. Es ist also sowohl objektorientiert als auch imperativ/prozedural.
Man sollte den OOP Ansatz von PHP nicht kleiner darstellen als er tatsächlich ist.

Unterschied und Vorteil von OOP

PHP stellt damit eine anwendbare Möglichkeit zur Verfügung OOP Lösungen zu implementieren. Im Gegensatz zur prozeduralen Programmierung hat man in der objektorientierten Programmierung die Möglichkeit seinen Klassen und Objekten eine Bedeutung zu geben, diese durch das Programm zu transportieren und sie in Beziehung zueinander zu stellen. Mit einem aussagekräftigen Namen weiß jeder, dass ein Auto einen von A nach B bringt. Bei der prozeduralen Programmierung kann man zwar den Schlüssel zum starten des Fahrzeugs verwenden aber es nicht so, dass das Zündschloss als Teil des Fahrzeugs verstanden wird sondern ein eigenständiges Dasein besitzt – der Programmcode ist sehr viel gelöster und um so unübersichtlicher je mehr Funktionalität dazu kommt. Die Objektorientierung setzt die Objekte also in Beziehung. Nicht nur durch Vererbung, dass ein Auto z.B. ein Fahrzeug ist, oder das ein Auto ein Zündschloss hat, es können auch mehrere Schlüsselarten verwendet werden ohne den vorhandenen Code ändern zu müssen. Ein Zündschlüssel kann so z.B. eine elektronische Variante sein ohne das man dabei Variablen oder Funktionen im Code anpassen muss. Wir erhalten eine Programmierung die einfacher zu ergänzen ist oder auch komplett ausgetauscht werden kann ohne die unzähligen Stellen im Programmcode ändern zu müssen in denen diese verwendet werden. Man merkt, dass die Objektorientierung mehr ist als das verwenden von Objekten und Klassen, es ist eine Möglichkeit Sachverhalte zu beschreiben und in Beziehung zueinander zu bringen. Wir können einem Zundschloss beibringen mit verschiedenen Schlüsseln umzugehen ohne, dass wir das Schloss selbst, bzw. die Funktionssignatur, sprich die Parameter, ändern müssen. Wir legen also mehrere Klassen als Schlüsselarten an und mehrere Klassen zur Verarbeitung des an das Zündschloss übergebenen Typs von Schlüssel. Viele dieser Problemstellungen wurden aber schon einmal gelöst, gründlich untersucht und in abstrakten Katalogen veröffentlicht. Man nennt dies Entwurfsmuster.

SPL (Standard PHP Library) und Vererbung

Ein besonderes Augenmerk sollte man auf die SPLhaben, denn neben der Verwendung als Basisklasse zur Vererbung, bieten die Klassen der SPL eine effizientere Verarbeitung von oft benötigten Algorithmen. Die objektorientierte Programmierung in PHP sollte die SPL nicht vernachlässigen und ich kann nur empfehlen diese Klassen und Interfaces bei der Vererbung zu verwenden.

Fehlende Konzepte

Leider gibt es in PHP noch einige Konzepte die ich sehr vermisse. Polymorphie und Methodenüberladung (Overloading), wobei letzteres helfen würde so manch merkwürdiges Konstrukt in PHP zu verhindern, werden hierbei oft angeführt. Bei der Polymorphie ist es im Moment so, dass man nur mehrere Interfaces auf einmal vererben kann.

Entwurfsmuster

Design Patterns sind Problemlösestragien und nicht Problemlösungen

Gleiche Klassen sind oft sehr verschieden da vor allem dem Zweck nach entworfen. Eine Waschanlage versteht ein Auto ganz anders als eine Werkstatt. Wenn man nun Betreiber einer Waschanlage ist, dann interessiert ein Zündschloss recht wenig, dass ist was für den Besitzer oder die Werkstatt. Es macht also keinen Sinn der Anlage zu erklären, dass ein Auto mit dem Zündschloss gestartet wird. Ähnlich verhält es sich mit den Entwurfsmustern, Sie müssen auf den Zweck abgestimmt angewendet werden. Ein Entwurfsmuster ist keine Lösung sondern eine Lösungsstrategie. Man kann die abstrakte Darstellung und Zusammenhänge verwenden um eigene Lösungen leichter zu konstruieren. Eine Hilfestellung zu sehr bekannten und untersuchten OOP-Problemstellungen. Ein weiterer Vorteil ist, dass ein Programmierer diese Entwurfsmuster erkennt und daraus ableiten kann wie diese funktionieren sollten.
Mit dem Object Oriented Programming ist es in jedem Fall einfacher die Intention des vorherigen Programmierers oder der zuvor selbst programmierten Klassen zu verstehen.

Das MVC-Pattern

Eingabe, Verarbeitung und Ausgabe.

Nehmen wir als Beispiel die Implementierung einer über eine URL Rewriting basierenden index.php die gerade dabei ist, eine anfragebasierte Seite auszuführen. Man würde dies imperativ folgendermaßen lösen.

Weiter gehen wir davon aus, dass wir dies in prozeduraler Form lösen möchten.

Wir haben es jetzt so gelöst, dass wir unsere Code nicht mehr ändern müssen wenn sich an der Funktion etwas ändern sollte müssen wir nicht durch die ganzen Programmstellen gehen an denen diese Funktion angewendet wird. Aber es gibt einige Nachteile die erst dann zum Vorschein treten wenn das Programm wächst. Wir haben Funktionen die zwar in Beziehung miteinander stehen aber in der Programmierung diese Beziehung nicht erkennen lassen da es sich hierbei nur um Funktionen handelt. Es könnte daher sein, dass man das parsen einer Seite auch einfach an einer anderen Stelle einbaut und der Zusammenhang dieser Funktionen unberücksichtigt bleibt. Es wird z.B. nicht mehr ermittelt ob es sich um eine Seite handelt die tatsächlich existiert und ob eine default Page verwendet werden soll. Ein weiterer Nachteil ist, dass die globalen Variablen ebenfalls lose herumfliegen und keine Beziehungen erkennen lassen. Mit der Objektorientierung und der Anwendung eines Enwurfsmuster wie dem MVC-Pattern kann man aber verhindern, dass Programme so programmiert werden, dass Algorithmen übergangen oder Eigenschaften (Variablen) ohne Bezug bleiben.

Was wir hiermit erreichen ist, dass wir den Zugriff auf die Funktionen/Methoden und Variablen/Eigenschaften kapseln, man spricht von Datenkapselung. Wir stellen nicht nur Funktionen zur Verfügung sondern bestimmen auch wie diese verwendet werden sollen. Um die Klasse überhaupt verwenden zu können, muss diese im Konstruktor konfiguriert werden. Erst mit einer Instanz können wir eine Seite parsen und davon abhängige Beziehungen werden ausgeführt.

Wer sich das MVC Pattern ansieht wird noch auf viele weitere Vorteile der Objektorientierung treffen. Zwar ist die Planung und Konzeption von objektorientierten Lösungen sehr viel aufwändiger aber gerade größere Projekte können davon stark profitieren. Die Objektorientierung muss daher auch viel durchdachter sein. Man muss berücksichtigen ob man die Beziehungen auch richtig abbildet und eine geeignete Schnittstelle zur Verfügung stellen die auf Änderungen besser reagieren kann als man das mit prozeduraler Programmierung könnte. Denn der Quellcode entwickelt sich ständig weiter und die Anforderungen ändern sich im Laufe der Zeit.

Das letzte Code-Beispiel hat natürlich noch recht wenig mit dem MVC Design-Pattern zu tun aber die Grundlage dafür ist geschaffen. Man würde den Dispatcher mit einen Front-Controller in Beziehung bringen. Man könnte sich folgendes vorstellen.

Der Code ist recht trivial und wenig durchdacht, aber als Beispiel sollte es genügen. Eine recht gute Hilfe zur Thematik bietet das Zend Framework 1 sowie in Version 2. Mit diesen beiden Frameworks bekommt man sehr viel Objektorientierung vermittelt. Es dauert eine Weile bis man sich eingearbeitet hat aber der Aufwand lohnt sich. Viele Firmen setzen Kenntnisse im Zend Framework vorraus und ich bedanke mich bei jedem Programmierer der das Zend Framework verwendet, dass erspart mir viel Einarbeitungszeit.

Programmierstil

Konventionen beachten

Es gibt nicht nur den persönlichen Programmierstil. Wie einigen aufgefallen sein könnte verwende ich recht wenige Leerzeichen und Leerzeilen. Mich stören diese – Wenn dort steht

dann bekomm ich Magenkrämpfe. Wenn z.B. etwas nicht eingerückt wird, dann landet es bei mir in der Kategorie unbrauchbar. Das sind aber subjektive Einschätzungen und genau aus diesem Grund gibt es zu den meisten Projekten gewisse Codingstandards an die man sich unbedingt halten sollte. Dort wird festgelegt wie breit ein Tab sein muss wieviel Zeichen pro Zeile oder ob Camel-Case-Notation verwendet wird. C++, Java und PHP haben meiner Meinung nach die beste Syntax und ermöglichen einen sauberen Programmierstil den man hinterher auch noch nachvollziehen kann. Die Camel-Case-Notation ist bei vielen beliebt und sinnvoll. Auch wenn man auf den Anweisungsblock {} verzichten kann sollte man es nicht tun, es dient der besseren Lesbarkeit. Dinge wie <?= $var ?> sind spätestens mit PHP 6 nicht mehr verwendbar und waren für mich schon immer ein No-Go, da diese Option deaktiviert werden kann, schlussendlich ganz wegfällt. Es war für mich nicht sinnvoll diese Abkürzung zu verwenden. Das hat sich dann bemerkbar gemacht als ich die kompletten Templates eines CMS ändern musste. Da hat mir der Vorgänger ganz schön Arbeit gemacht und in einigen Tutorials wird selbiges auch noch empfohlen. Man muss sich schon etwas über PHP informieren wenn man damit arbeitet. Gerade weil PHP eine Einsteigersprache ist witmen manche der Programmierung mit PHP keine Aufmerksamkeit, dabei geht es gar nicht um die verwendete Sprache sondern viel eher um guten Stil. Der wird leider viel zu oft vernachlässigt mit der Begründung „Es ist doch nur PHP“. Und der Denkzettel kommt dann wenn man alle <?= $var ?> ersetzen muss. Es macht bestimmt keinen Spaß in einer Programmiersprache zu programmieren die man selbst nicht würdigt.

Die Frage wie man ein besserer Programmierer wird kann man nur damit beantworten, dass man es sich bei anderen abschaut aber eben nicht das falsche abkuckt. Gut zu programmieren hat viel mit Erfahrung zu tun. Nach einer gewissen Zeit eignet man sich, zu anderem mit Entwurfsmustern, verschiedene Strategien an und wird im Laufe der Zeit ziemlich gut darin abzuschätzen welche Anforderungen an eine Klasse gestellt werden könnten. Auch das kalkulieren des Aufwands wird irgendwann zu einer Routine. Der Kunde fragt nach dem Aufwand für Funktion x und im selben Moment geht man gedanklich durch die dafür benötigten Programmstukturen. Diese Erfahrungswerte will ich hier vermitteln.

Den Kern erfassen

Man programmiert und kommt doch nicht zum Ende, es lässt sich nicht einschätzen und verursacht viele Fehler. Dabei umschreibt man oft den Kern der Sache. Manche Dinge lassen sich mit ein paar Zeilen besser lösen als mit 100 Zeilen. Wenn es z.B. übliche also recht triviale Programmzeilen betrifft, dann sollte man versuchen es so einfach wie möglich zu lösen. Klein ist fein und spart Kosten, macht ein Programm einschätzbar und übersichtlicher. Viele Programme sind ausufernd und einige Klassen erledigen Sachen für die sie eigentlich nicht verantwortlich sind. Etwas geschickter ist es natürlich, wenn man sich andere Möglichkeiten einfach offen hält Sie aber nicht hinzufügt. Featuring ist nicht unbedingt das beste aber man sollte darauf achten, dass der Programmcode wachsen kann ohne das viel geändert werden muss. Das kann man sich hervorragend am Zend Framework abschauen. Nach einiger Zeit merkt man, dass man viele Dinge viel einfacher lösen kann und so Komplexität verhindern kann.

Don’t Repeat Yourself

Für ganz triviale Dinge gilt dies natürlich nicht wie z.B. das einfache Iterieren durch Objekte. Dazu braucht man nicht unbedingt eigene Methoden. Anders verhält es sich bei immer wieder kehrenden Problemen. Man stelle sich nur vor, dass man eine Sequenz schon 20 mal verwendet hat und stellt plötzlich fest, dass ein Fehler drin ist. Alles was Copy & Paste zum Programm hinzugefügt wird ist schon vorneherein ein Kandidat. Alles was sich ändern könnte, fehler verursachen kann und öfters verwendet wird kann man in Methoden auslagern.

Verwende Wächter statt Verschachtelung

Ein Wächter ist eine Sequenz die zur Prüfung der Daten verwendet wird. Statt immer weiter in IF Strukturen zu verschachteln ist es oft möglich und sinnvoll sogenannte Wächter einzusetzen.

Gerade bei größeren Anweisungsblöcken macht das den Code sehr viel übersichtlichter.

Magic Numbers

Es ist recht verwirrend, wenn im Programmcode immer wieder irgendwelche Zahlenmengen auftreten die man nicht zurückverfolgen kann. Ich bräuchte nicht mal ein Beispiel um zu zeigen, dass 138 in diesem Text keiner nachvollziehen kann. Was könnte es sein woher kommt der Wert? Deshalb solche Zahlen in Variablen speichern mit aussagekräftigem Namen und notfalls die Herleitung dokumentieren.

Sinnvolle Kommentare

Kommentare helfen den Code zu verstehen zu viel davon bewirkt aber das Gegenteil, man muss eine For-Schleife durch einen Array nicht damit dokumentieren, dass ein Integerwert inkrementiert wird. Vieles am Programm ist selbsterklärend, wenn man solche Dinge dokumentiert tut man niemanden einen gefallen. Dokumentiert werden muss was nicht sofort ersichtlich ist. Es geht darum Hilfestellung bei der Herleitung der Funktion zu geben. Wenn ich eine Funktion habe addiere(x,y) dann brauch man dafür nun wirklich keine große Dokumentation. Ausnahmen bildet die Signatur einer Funktion, die Parameter und Rückgabewerte, diese sollte man immer Dokumentieren. Viele IDE’s sind darauf angewiesen diese Kommentare auszuwerten, so z.B. Eclipse PDT.

Programmiert wird in Englisch

Es kommt oft vor, dass ich plötzlich deutsch oder französisch dokumentierten und programmierten Quellcode lese. Das geht gar nicht.
Englisch ist nunmal der Standard und die Sprache die jeder ansatzweise verstehen sollte. Ausnahmen sollten hier nur dann zum Vorschein treten, wenn das entsprechende Wort im englischen wenig Sinn macht oder gar nicht existiert.

Arbeitszeiten notieren

Man sollte ganzheitliche oder sequenzielle Zeiterfassung betreiben. Das hilft in späteren Projekten eine Referenz zu haben. Man kann den Aufwand oft abschätzen in dem man vergleichbare Projekte heranzieht.


Ich hoffe dieser kleine Artikel konnte einen kurzen Abriss zur objektorientierten Programmierung liefern und ein paar Regeln für guten Programmierstil aufzeigen. Ich will ja keinem was auf’s Auge drücken, es bleibt einem selbst überlassen wie man Programmiert. Ich hoffe die wichtigsten Punkte getroffen zu haben und dem ein oder anderen einen Hilfreichen Tip vermittelt zu haben. Kritik ist erwünscht, positives Feedback ebenfalls.

Leave a Reply

Your email address will not be published. Required fields are marked *

*