größeres Projekt in PHP mit OOP
Mark
- programmiertechnik
Hallo,
bisher habe ich hauptsächlich prozedural "gecodet" und höchstens mal eine (fremde) Klasse eingebunden. In letzter Zeit habe ich mich dann mal ausführlicher mit OOP beschäftigt und finde das auch alles ganz schön und gut. Die Beispiele in den zahlreichen Tutorials habe ich kapiert und finde den OOP-Ansatz auch ganz elegant!
Nur sind das meist recht simple Beispiele mit ein paar Zeilen Code, und ich frage mich nun: wie geht man ein größeres Projekt mit OOP an? Also z.B. eine Web-Applikation mit Registrierung, Log in, User-Bereich, Artikel verfassen, Kommentieren usw.?
Bisher habe ich das etwa so gemacht:
$action = irgendwie_die_action_ermitteln();
switch($action)
{
case 'register':
include('register.php');
break;
case 'login':
include('login.php');
break;
case 'sonstwas':
include('sonstwas.php');
break;
}
...also die verschiedenen Bereiche aufgeteilt in einzelne Dateien und nach bedarf "includiert".
Wie mache ich das mit OOP? Als erstes fällt mir so etwas ein:
$meineKillerApplikation = new KillerApplikation();
switch($meineKillerApplikation->action)
{
case 'register':
$meineKillerApplikation->register();
break;
case 'login':
$meineKillerApplikation->login();
break;
case 'sonstwas':
$meineKillerApplikation->sonstwas();
break;
}
Nun hat sich mein Hauptprogramm kaum geändert und ich habe eine riesige unübersichtliche Klasse mit unzähligen Methoden, die vorher in einzelnen Dateien untergebracht waren.
Also teile ich das Ganze in verschiedene Klassen auf:
$action = irgendwie_die_action_ermitteln();
switch($action)
{
case 'register':
include('userverwaltung.class.php')
$userverwaltung = new Userwerwaltung();
$userverwaltung->register();
break;
case 'login':
include('userverwaltung.class.php')
$userverwaltung = new Userwerwaltung();
$userverwaltung->login();
break;
case 'sonstwas':
include('sonstwas.class.php')
$sonstwas = new Sonstwas();
}
Ist das jetzt elegantes OOP??? Mein Hauptprogramm ist ja immer noch prozedural und ist im Prinzip kaum anders als die erste Variante.
Hilfreich wäre es, sich mal ein "elegant" und O. o. programmiertes Skript anschauen zu können. Ein paar bekannte wie phpBB oder Wordpress habe ich mir bereits angeschaut - eleganter OOP-Code ist das aber nicht gerade... Kennt jemand ein gut programmiertes größeres Skript?
Danke!
Mark
...noch ein paar weitere Fragen zu OOP:
* Wenn ich innerhalb einer Klasse weitere andere Klassen benötige (z.B. eine DB-Abstraktions-, Parser- oder CAPTCHA-Klasse in einer Klasse zum Anzeigen und Eintragen von Kommentaren), wie binde ich diese am besten ein?
So geht es zwar...
class A
{
public $something;
function A()
{
require('AnotherClass.php');
$this->something = new AnotherClass();
}
}
... aber das sieht schon wieder ziemlich nach Spaghetti-Code aus! Das require ist ja, als wäre in function A die Klasse AnotherClass notiert wäre. Und im Hauptprogramm möchte ich die Klasse vielleicht noch nicht pauschal includen, da ich sie nur in ein paar bestimmten Fällen benötige (ja, __autoload() kenne ich, das macht aber doch im Prinzip auch nichts anderes).
* Wie ist es mit globalen Variablen innerhalb von Klassen? Darf man (im Sinne von gutem Programmierstil) innerhalb einer Methode auf $_POST['sonstwas'] zurückgreifen? Oder wie ist es mit globalen Einstellungen die ich in einem Array habe (z.B. $config['foo'] = 'bar')? Darf ich diese mit "global" einbinden oder sollte ich sie immer als Parameter übergeben?
* Wenn ich ein paar Grundfunktionen in einer Datei auslagern will, ist es immer sinnvoll, diese in eine Klasse zu packen und so mit Funktionen::meine_funktion() aufzurufen?
Nochmal Danke!
Mark
* Wenn ich innerhalb einer Klasse weitere andere Klassen benötige (z.B. eine DB-Abstraktions-, Parser- oder CAPTCHA-Klasse in einer Klasse zum Anzeigen und Eintragen von Kommentaren), wie binde ich diese am besten ein?
Beispiel:
Ich habe mir eine MySQL-Klasse angelegt, in der im Prinzip (fast) alles drin ist, um auf die Datenbank zuzugreifen (wird folglich in den meisten anderen Klassen benötigt):
class example extends mysql {
function haumichtot() {
...
}
...
}
Auf die Methoden der Elternklasse greifst Du via parent::methodenname() zu.
* Wie ist es mit globalen Variablen innerhalb von Klassen? Darf man (im Sinne von gutem Programmierstil) innerhalb einer Methode auf $_POST['sonstwas'] zurückgreifen? Oder wie ist es mit globalen Einstellungen die ich in einem Array habe (z.B. $config['foo'] = 'bar')? Darf ich diese mit "global" einbinden oder sollte ich sie immer als Parameter übergeben?
verwende entweder Superglobals oder binde Deine Variablen über den Methodenaufruf ein
Gruß, Samoht
class example extends mysql {
function haumichtot() {
...
}...
}
mysql ist in diesem Fall natürlich der Name der vorhandenen mysql-Klasse
Gruß, Samoht
--
fl:| br:> va:) ls:< n4:( ss:) de:] js:| mo:}
"Computer games don't affect kids; I mean if Pac-Man affected us as kids, we'd all be running around in darkened rooms, munching magic pills and listening to repetitive electronic music."
(Kristian Wilson, Nintendo, 1989)
Moin!
class example extends mysql {
function haumichtot() {
...
}...
}
>
> mysql ist in diesem Fall natürlich der Name der vorhandenen mysql-Klasse
Das ist kein sehr eleganter Name, weil er mit der Standardklasse mysqli verwechselt werden kann, die PHP mitliefert.
Überhaupt sollte man so langsam mal das alte mysql-Interface ruhen lassen. Es ist technisch rückständig und kann nicht mehr alle Funktionen unterstützen, die MySQL heutzutage so bietet.
- Sven Rautenberg
--
"Love your nation - respect the others."
Überhaupt sollte man so langsam mal das alte mysql-Interface ruhen lassen. Es ist technisch rückständig und kann nicht mehr alle Funktionen unterstützen, die MySQL heutzutage so bietet.
Und genau dann macht eine Klasse Sinn, die für die Datenbankzugriffe zuständig ist.
Dadurch kann man es dem Anwender überlassen, ob er mysqli oder mysql einsetzen will. Denn einige Hoster bieten kein mysqli an. In diesem Fall braucht man dazu nur eine Klasse auszutauschen.
Moin!
Überhaupt sollte man so langsam mal das alte mysql-Interface ruhen lassen. Es ist technisch rückständig und kann nicht mehr alle Funktionen unterstützen, die MySQL heutzutage so bietet.
Und genau dann macht eine Klasse Sinn, die für die Datenbankzugriffe zuständig ist.
Dadurch kann man es dem Anwender überlassen, ob er mysqli oder mysql einsetzen will. Denn einige Hoster bieten kein mysqli an. In diesem Fall braucht man dazu nur eine Klasse auszutauschen.
Wenn ein Hoster so rückständig ist, dann bietet er mit Sicherheit auch keine aktuelle Version von MySQL an - und dann gehen noch ganz andere Dinge nicht, die man lieber haben wollen sollte.
- Sven Rautenberg
echo $begrüßung;
* Wenn ich innerhalb einer Klasse weitere andere Klassen benötige (z.B. eine DB-Abstraktions-, Parser- oder CAPTCHA-Klasse in einer Klasse zum Anzeigen und Eintragen von Kommentaren), wie binde ich diese am besten ein?
So geht es zwar...
class A
{
public $something;
function A()
{
require('AnotherClass.php');
$this->something = new AnotherClass();
}
}
>
> ... aber das sieht schon wieder ziemlich nach Spaghetti-Code aus! Das require ist ja, als wäre in function A die Klasse AnotherClass notiert wäre.
Diese Verschachtlung gibt es nach dem Parsen nicht mehr. Klassen und eigenständige Funktionen werden grundsätzlich global angelegt. Sie so zu verschachteln bringt nichts außer Unübersichtlichkeit.
> Und im Hauptprogramm möchte ich die Klasse vielleicht noch nicht pauschal includen, da ich sie nur in ein paar bestimmten Fällen benötige (ja, \_\_autoload() kenne ich, das macht aber doch im Prinzip auch nichts anderes).
Wenn du require und Konsorten (\*\_once wird besser sein, denn du kannst die Klasse ja schließlich an mehreren Orten benötigen wollen.) ohne Bedingung in deinen Quelltext einfügst, wird sie jedes Mal mit geparst. Bei \_\_autoload() erst dann, wenn sie tatsächlich verwendet wird. Da es ohne die SPL nur ein \_\_autoload() geben kann, solltest du darauf in Funktionsbibliotheken, die du unabhängig vom Anwendungsprogramm halten willst, verzichten und das nur dem Anwender für seine eigenen Zwecke überlassen. Ansonsten ist man auf die Abhängigkeit der Benennung einer Klasse zu deren Speicherort abhängig. Zumindest ist das eine gängige Methode, \_\_autoload() plus Ordnung im Dateisystem zu haben.
Allgemein üblich ist es, am Anfang der jeweiligen Datei alle benötigten Referenzen zu inkludieren. Das im Hauptprogramm zu machen ist nicht gerade übersichtlich.
> \* Wie ist es mit globalen Variablen innerhalb von Klassen? Darf man (im Sinne von gutem Programmierstil) innerhalb einer Methode auf $\_POST['sonstwas'] zurückgreifen? Oder wie ist es mit globalen Einstellungen die ich in einem Array habe (z.B. $config['foo'] = 'bar')? Darf ich diese mit "global" einbinden oder sollte ich sie immer als Parameter übergeben?
Das kommt darauf an. Pauschal kann man das nicht beantworten. Soll die Funktion mit beliebigen Daten umgehen können, dann bieten sich Parameter an. Ist sie hingegen auf Teile des HTTP-Requests spezialisiert, dann kann sie direkt darauf zugreifen.
> \* Wenn ich ein paar Grundfunktionen in einer Datei auslagern will, ist es immer sinnvoll, diese in eine Klasse zu packen und so mit Funktionen::meine\_funktion() aufzurufen?
Auch hier gibt es kein klares Ja oder Nein. Natürlich kann man triviale Dinge auch von Klassen ausführen lassen. Du wirst doch sicher die Funktionalität einer bestimmten übergeordneten Einheit zuweisen können. Beispielsweise ist eine Maskier-Funktion für HTML als Methode der Klasse gut aufgehoben, die sich um die Ausgabe kümmert.
echo "$verabschiedung $name";
echo $begrüßung;
Nur sind das meist recht simple Beispiele mit ein paar Zeilen Code, und ich frage mich nun: wie geht man ein größeres Projekt mit OOP an? Also z.B. eine Web-Applikation mit Registrierung, Log in, User-Bereich, Artikel verfassen, Kommentieren usw.?
Vor diesen Probleme standen bereits andere. Die Antwort darauf ist meist ein Framework, das immer wiederkehrende Arbeiten erledigt und auch gleich noch für Struktur sorgt, wenn man sich dem Konzept des Frameworks anpasst.
Ist das jetzt elegantes OOP??? Mein Hauptprogramm ist ja immer noch prozedural und ist im Prinzip kaum anders als die erste Variante.
Eleganz liegt im Auge des Betrachters. Hinzu kommt noch, dass verschiedene Ansätze, ein Problem zu lösen, in sich elegant aussehen können, aber nicht unbedingt miteinander vermischbar sind.
Hilfreich wäre es, sich mal ein "elegant" und O. o. programmiertes Skript anschauen zu können. Ein paar bekannte wie phpBB oder Wordpress habe ich mir bereits angeschaut - eleganter OOP-Code ist das aber nicht gerade... Kennt jemand ein gut programmiertes größeres Skript?
Von den beiden Beispielen hört man von mehr Lücken als es Installationen gibt :-) Das Problem an vielen "unelegant" ausgeführten Projekten ist, dass sie einfach schnell angefangen wurden, dann gewachsen sind, und schon von vorn herein keine solide Struktur hatten. Hinterher Ordnung reinzubringen ist oft mit kompletter Neuentwicklung verbunden.
Such mal nach "php framework". Diesen zugrunde liegt die Aufgabenstellung, Struktur und Hilfsmittel für alle möglichen Anwendungen bereitzustellen.
Ansonsten kann ich nur raten, nicht nur Empfehlungen zu lesen, sondern selbst alles mögliche auszuprobieren, die Eigenschaften der Systeme kennenzulernen. Einige Wege entpuppen sich als Sackgassen für bestimmte Aufgabenstellungen, können aber für andere Projekte nützlich sein. Es gibt einen Konsens für Dinge, die man gar nicht machen darf (z.B: Sicherheitslücken einbauen, undokumentierte Codewüsten erstellen), aber dann hört es eigentlich schon auf. Der übriggebliebene Rest ist Entscheidung aufgrund eigener (zu sammelnder) Erfahrung.
echo "$verabschiedung $name";
...auch Dir dedlfix Dankeschön für Deine Antwort. Frameworks für die Basics gibt es tatsächlich eine Menge. Allerdings ist mein Hauptprogramm auch wieder prozedural, wenn ich so eines oder mehrere einbinde.
Mark
echo $begrüßung;
...auch Dir dedlfix Dankeschön für Deine Antwort. Frameworks für die Basics gibt es tatsächlich eine Menge. Allerdings ist mein Hauptprogramm auch wieder prozedural, wenn ich so eines oder mehrere einbinde.
Das muss nicht sein. Schau dir doch mal das Zend Framework an. Wenn du dies verwendest, besonders den Zend_Controller-Teil, dann bleibt kaum noch "Hauptprogramm" übrig :-)
echo "$verabschiedung $name";
Moin!
Nur sind das meist recht simple Beispiele mit ein paar Zeilen Code, und ich frage mich nun: wie geht man ein größeres Projekt mit OOP an? Also z.B. eine Web-Applikation mit Registrierung, Log in, User-Bereich, Artikel verfassen, Kommentieren usw.?
Indem man zuerst die kleinsten Aufgaben und Dinge mit thematisch eng begrenzten Objekten erfüllt, um dann neue, darauf aufbauende Aufgaben mit weiteren Objekten zu erledigen, die die ersten Objekte benutzen, und so weiter.
$meineKillerApplikation = new KillerApplikation();
Das ist die falsche Denkweise.
In der Regel hast du Objekte für die absoluten "Basics".
Diese "Basics" zerfallen in zwei grundsätzlich unterschiedliche Teile: Erstens Objekte, die mit der "Außenwelt" kommunizieren, und zweitens Objekte, die komplett für sich alleine stehen und ohne Außenwelt funktionieren.
Diese Unterscheidung ist vor allem wichtig, wenn man den Entwicklungsansatz "test driven design" verfolgt: Man schreibt zuerst für jedes Objekt und dessen Methoden, die entstehen sollen, mindestens einen Test, der erst dann erfolgreich durchlaufen wird, wenn man das Objekt korrekt programmiert hat. Das bedeutet für Objekte, die mit der Außenwelt kommunizieren, einen deutlich größeren Aufwand, weil der Test vorher die korrekte Simulation der Außenwelt herstellen muß, und hinterher alles wieder aufräumen.
Beispiel: Wenn ein Objekt aus einer Datei lesen soll, dann wird der Test vorher eine Datei mit einem beliebigen Dateinamen anlegen und etwas reinschreiben müssen und diesen Namen dann dem Objekt übergeben, damit hinterher geprüft werden kann, ob die Datei korrekt gelesen wurde. Und damit sich solche Dateien nicht endlos ansammeln und stören, muß die Datei hinterher auch wieder gelöscht werden.
In diesem Zusammenhang sehr empfehlenswert: http://www.lastcraft.com/first_test_tutorial.php sowie http://www.lastcraft.com/simple_test.php.
Nun hat sich mein Hauptprogramm kaum geändert und ich habe eine riesige unübersichtliche Klasse mit unzähligen Methoden, die vorher in einzelnen Dateien untergebracht waren.
Das liegt an deinem Denkansatz, zuerst ein riesiges Objekt zu bauen, in dem "irgendwas" passiert.
Hilfreich wäre es, sich mal ein "elegant" und O. o. programmiertes Skript anschauen zu können. Ein paar bekannte wie phpBB oder Wordpress habe ich mir bereits angeschaut - eleganter OOP-Code ist das aber nicht gerade... Kennt jemand ein gut programmiertes größeres Skript?
Ich glaube kaum, dass wirklich GROSSE Projekte dir hinsichtlich eines OOP-Ansatzes weiterhelfen werden, da du ja dort nur die fertigen Resultate siehst, aber nicht die Idee, die dahintersteckt und begründet, warum die Einzelteile so sind, wie sie sind.
In OOP kommen viele, oft sehr unterschiedliche, Einzelteile vor. Typisch wäre beispielsweise:
a) eine Kapselklasse für die klassischen mysql_*-Funktionen (braucht man ab PHP 5 mit mysqli nicht mehr, bzw. löst es anders).
b) eine Klasse für den Mailversand
c) eine Klasse fürs Loggen (siehe als exzellentes Beispiel das Tutorial oben)
d) Klassen für Datenobjekte (funktioniert elegant mit mysqli)
Es gehört zum OOP unbedingt dazu, sich auch mit Designpattern auseinanderzusetzen. Patterns, die sehr häufig vorkommen, sind z.B. das Singleton-Pattern oder das Factory-Pattern.
- Sven Rautenberg
Hallo Sven,
Danke, das hat weitergeholfen, schaue mir gerade die Tutorials an.
Mark