Modulares Programmieren mit PHP
Thorsten Steffen
- programmiertechnik
hio,
weil mir solangsam der Schädel platzt, muss ich nun einfach mal in die Runde frage und ein paar Anregungen und Meinungen einholen.
Ein paar kleine Klassen, die ich schon mal programmiert hatte in PHP will ich jetzt zu einem, nennen wir es Framework zusammensetzen.
Diese Klassen sollen nun erstmal so weit wie möglich eigenständige Module sein, die zwar teilweise auf andere Klassen angewiesen sind, aber soweit möglich auch ohne diese auskommen.
ein beispiel, es gibt eine fileUpload-Klasse, die hat die Aufgabe eine Datei die per POST hochgeladen wurde in ein bestimmtes Verzeichnis zu verschieben. Nun gibts verschiedene Filter und Regeln, die man definieren kann um zu entscheide wird die Datei akzeptiert oder nicht.
So weit so gut, nun hab ich entschieden diese um eine Klasse errorReporting zu erweitern, welche Fehlermeldungen und Ereignismeldungen verwaltet. Weiter gibts eine Klasse die Beispielsweise Thumbgrafiken erzeugen kann.
Meine erste Idee war folgende. Die errorReporting-Klasse als Basisklasse fast aller Klassen zu verwenden, da Fehler überall auftreten können, die thumbnails selbst sind hingegen nicht so elementar für meine fileUpload-Klasse, deswegen erzeuge ich nach Bedarf eine Instanz davon.
also,
class fileUpload extends errorReporting {
function createThumb() {
$this->createThumb = new thumbnail();
....
}
Nun ist aber eigentlich auch so, das ja meine fileUpload-Klasse selbst nicht wirklich davon abhängig ist Fehlermeldungen speichern zu können. So mache ich sie jedoch abhängig davon. Wäre es vielleicht nicht sinnvoller auch die errorReporting-Klasse nur bei Bedarf zu Instanzieren?
Macht es Sinn in der Praxis, alle Klassen die man zwar brauchen könnte, jedoch nicht unbedingt benötigt in einer Klasse bei Bedarf zu Instanzieren? So überlegt könnte ich ja eigentlich fast alles so handhaben, da beinahe jede Klasse bis zu einem gewissen Punkt alleine klar kommt. Oder leidet die übersichtlichkeit und Transparenz irgendwann darunter?
Ich mache mir gerade megaviele Gedanken, wie ich Klassen so gestalten kann, die sie so eigentständig wie möglich funktionieren und welche Aufbau wirklich sinn macht. Vielleicht kann jemanden ein paar Tipps geben, der sich schon intensiver damit auseinandergesetzt hat, oder kennt ein Tutorial das nicht auf Einsteigerniveau liegt, davon gibts genug.
gl & hf
Thorsten
Hallo Thorsten,
Ganz am Anfang: Vielleicht findest Du unter </archiv/2002/12/31778/> auch ein paar interessante Anregungen.
So weit so gut, nun hab ich entschieden diese um eine Klasse errorReporting zu erweitern, welche Fehlermeldungen und Ereignismeldungen verwaltet. Weiter gibts eine Klasse die Beispielsweise Thumbgrafiken erzeugen kann.
Hmmm. Ich an Deiner Stelle würde Backend und Frontend sauber trennen. Du hast dann ein paar Klassen, die die Backgroundarbeit erledigen (fileUpload, thumbnail, etc.) und ein paar Klassen, die sich um die Benutzerinteraktion kümmern und die Backendklassen verwenden.
Nun ist aber eigentlich auch so, das ja meine fileUpload-Klasse selbst nicht wirklich davon abhängig ist Fehlermeldungen speichern zu können. So mache ich sie jedoch abhängig davon. Wäre es vielleicht nicht sinnvoller auch die errorReporting-Klasse nur bei Bedarf zu Instanzieren?
Du kannst es ja wie PEAR machen, Du kannst eine Fehlermeldungsklasse definieren, und diese bei Bedarf als Rückgabewert von Funktionen zurückgeben. Du kannst dann in Deinen Scripten prüfen, ob ein "normaler" Rückgabewert zurückgegeben worden ist, oder das Fehlerobjekt.
Macht es Sinn in der Praxis, alle Klassen die man zwar brauchen könnte, jedoch nicht unbedingt benötigt in einer Klasse bei Bedarf zu Instanzieren?
Ja.
Oder leidet die übersichtlichkeit und Transparenz irgendwann darunter?
Wieso sollte sie?
Ich mache mir gerade megaviele Gedanken, wie ich Klassen so gestalten kann, die sie so eigentständig wie möglich funktionieren und welche Aufbau wirklich sinn macht.
Das ist gut so. Ein gutes Konzept ist immer sehr wichtig, warscheinlich das Essenziellste einer guten Software. (neben der Dokumentation)
oder kennt ein Tutorial das nicht auf Einsteigerniveau liegt, davon gibts genug.
Der Archivlink oben... ;-)
gl & hf
gl? hf?
Grüße,
Christian
Hi Christian,
gl? hf?
good luck & have fun :)
Hallo!
Ganz am Anfang: Vielleicht findest Du unter </archiv/2002/12/31778/> auch ein paar interessante Anregungen.
jepp ;-)
Hmmm. Ich an Deiner Stelle würde Backend und Frontend sauber trennen. Du hast dann ein paar Klassen, die die Backgroundarbeit erledigen (fileUpload, thumbnail, etc.) und ein paar Klassen, die sich um die Benutzerinteraktion kümmern und die Backendklassen verwenden.
Ich für mich komme jetzt denke ich mit Backend-Klassen recht gut zurecht. Mir fehlt jetzt noch ein Basismodul/-klasse und Frontend-Klassen. Da fehlt mir zur Zeit noch eine Vorstellung für, wie ich das jetzt z.B. in PHP machen soll. Was macht so eine Frontend-Klasse genau und wie/wo wird die instanziert?
Um beim Beispiel Bilder-Upload zu bleiben, welche Klassen brauche ich alle hierfür? Ist die Ausgabe-Klasse (smarty) hier hier ein Backend-Modul?
Also von vorne:
Ich habe eine Startseite, auf der ist ein Link zum Upload-Formular.
Dieser link geht wohin? Vermutlich auf das Upload-Script, oder? OK.
Dann wird das Upload-Script geladen.
In dem Upload-Script wird dann meinetwegen ein Basis-Modul geladen, wo ich auch noch nicht genau weiß was es genau machen soll, auf alle Fälle hat es erstmal globale Daten wie den Standard-Pfad und die Standard-url.
Die Uplaod-Klasse wird erstmal nicht geladen, da ich die ja erst später brauche.
Dann wird die Smarty-Klasse geladen, und mir deren Hilfe das HTML-Forumlar generiert und ausgegeben.
Jetzt hat der User im Browser dieses Formular.
Er wählt eine Datei aus und klickt auf "submit".
Der POST-Request geht wieder an das Upload-Script.
Und hier weiß ich jetzt nicht mehr weiter. < < <
Es wird wieder das Upload-Script geladen,
dieses läd das Basis-Modul,
und wer nimmt jetzt die Daten entgegen? Soll ich das in das upload-Script reincoden? Vermutlich kommt hier eine von Dir genannte Frontend-Klasse ins Spiel, aber wie genau funktioniert das?
Wo wird diese Klasse genau geladen?
Wo wird eine Instanz erstellt?
Wie kommen die Daten in die Klasse?
Holt sich die Klasse die Daten selbst aus den Umgebungsvariablen?
Nur woher kennt die Klasse die beim POST Request verwendeten Parameter-Namen?
Woher weiß die Klasse das eine Datei mitgeschickt wird?
Woher weiß die Klasse an welches Modul die Daten übergeben werden müssen?
;-)
Viele Fragen, aber noch habe ich da beachtliche Verständnis-Probleme ;-)
Aber auch mit der Basisklasse bin ich noch nicht so ganz warm. Was soll die Klasse denn genau machen außer ein paar feste Daten wie root_path und root_url zur Verfügung zu stellen?
So wie sich das bei Euch immer anhört regelt die Basis-Klasse so ziemlich alles, alles läuft hierüber - nur wie sieht das praktisch aus? OK, ich könnte innerhab dir Klasse die benötigten Module einbinden, aber woher weiß ich welche Module benötigt werden?
Das ist gut so. Ein gutes Konzept ist immer sehr wichtig, warscheinlich das Essenziellste einer guten Software. (neben der Dokumentation)
Ja, bei mir verschiebt sich das Verhältnis von Programmieren => Konzeption vor allem zur Zeit da ich nicht mit einem falschen Konzept anfangen will ganz erheblich. Ich bin noch ein ganzes Stück davon entfernt "das sich der Kreis schließt" ;-)
Viele Grüße
Andreas
Hallo Andreas,
jepp ;-)
schon komisch, dass wir beide den selben Thread verlinken...
Um beim Beispiel Bilder-Upload zu bleiben, welche Klassen brauche ich alle hierfür?
Die Basisklasse, die Backendklassen und die Klasse für den Bilderupload, die von der Basisklasse abgeleitet ist.
Ist die Ausgabe-Klasse (smarty) hier hier ein Backend-Modul?
Ja. Frontend ist *nur* das, das *direkt* auf Benutzereingaben reagiert und "Ablaufslogik" enthält. (ich hoffe, Du verstehst, was ich meine)
Ich habe eine Startseite, auf der ist ein Link zum Upload-Formular.
Dieser link geht wohin? Vermutlich auf das Upload-Script, oder? OK.
Nicht ganz. Dieser Link geht zum Standardscript, das in diesem Fall (per URL-Parameter gesteuert) die Upload-Frontend-Klasse verwendet.
In dem Upload-Script wird dann meinetwegen ein Basis-Modul geladen, wo ich auch noch nicht genau weiß was es genau machen soll, auf alle Fälle hat es erstmal globale Daten wie den Standard-Pfad und die Standard-url.
s.o.
Die Uplaod-Klasse wird erstmal nicht geladen, da ich die ja erst später brauche.
Nein, die Upload-Frontend-Klasse brauchst Du jetzt immer, nur eine eventuelle existierende Backend-Klasse existiert noch nicht. Du kannst Dir unter "Frontend" ein Modul vorstellen, Du musst nicht unbedingt eine Klasse verwenden, eine Datei, die included wird oder eine Funktion könnte die aufgabe auch bewältigen.
Dann wird die Smarty-Klasse geladen, und mir deren Hilfe das HTML-Forumlar generiert und ausgegeben.
Exakt.
Jetzt hat der User im Browser dieses Formular.
Er wählt eine Datei aus und klickt auf "submit".
Der POST-Request geht wieder an das Upload-Script.
Genau.
Es wird wieder das Upload-Script geladen,
dieses läd das Basis-Modul,
Jain, es wird wieder das Standardscript geladen, das das Upload-Frontend startet.
und wer nimmt jetzt die Daten entgegen? Soll ich das in das upload-Script reincoden?
Das Upload-Frontend sollte sie enthalten.
Wo wird diese Klasse genau geladen?
Du meinst "included"? Vor der Verwendung, entweder werden alle Dateien mit allen Frontend-Klassen eingelesen, oder nur kondizional je nach Anfrage.
Wo wird eine Instanz erstellt?
An der Stelle, wo klar ist, dass das Upload-Frontend verwendet werden soll.
Wie kommen die Daten in die Klasse?
Superglobale, also $_GET, $_POST, $_FILE?
Holt sich die Klasse die Daten selbst aus den Umgebungsvariablen?
Ja.
Nur woher kennt die Klasse die beim POST Request verwendeten Parameter-Namen?
Sie hat sie selbst definiert.
Woher weiß die Klasse das eine Datei mitgeschickt wird?
Status-Flags, PHP-File-Upload-Handling funktionen...
Aber auch mit der Basisklasse bin ich noch nicht so ganz warm. Was soll die Klasse denn genau machen außer ein paar feste Daten wie root_path und root_url zur Verfügung zu stellen?
Im Prinzip gar nichts... :-)
So wie sich das bei Euch immer anhört regelt die Basis-Klasse so ziemlich alles, alles läuft hierüber
Hä?
Grüße,
Christian
P.S.: Alles, was ich hier schreibe, ist mit meiner Einstellung behaftet, wie ich es realisieren würde. Aber Du darfst nie aus den Augen verlieren: Es gibt tausende Möglichkeiten, das zu realisieren.
Hi Christian!
jepp ;-)
schon komisch, dass wir beide den selben Thread verlinken...
Hab mich auch gewudert ;-)
Die Basisklasse, die Backendklassen und die Klasse für den Bilderupload, die von der Basisklasse abgeleitet ist.
von der Basisklasse abgeleitet? Was bedeutet das schon wieder? Heißt die Frontendklasse Bilderupload wird von der Basisklase geladen(include) und instanziert(new...)? Oder erweiter mit extends...?
Ja. Frontend ist *nur* das, das *direkt* auf Benutzereingaben reagiert und "Ablaufslogik" enthält. (ich hoffe, Du verstehst, was ich meine)
immer etwas mehr ;-) Aber den Teil habe ich jetzt glaube ich auch.
Nicht ganz. Dieser Link geht zum Standardscript, das in diesem Fall (per URL-Parameter gesteuert) die Upload-Frontend-Klasse verwendet.
Also doch alles über ein Script. Dann läuftz das ganze also anders herum, das Basis-Script bindet das file-upload-Script ein, ich brauche als kein include("basis.modul.php") in jedem Script. OK. Und wie mache ich es das statt der URL mein basis-script aufgerufen wird? mod_rewrite? Wie habe ich mir das vorzustellen?
RewriteEngine On
RewriteRule ^(.*)$ /basis_script.php?params=$1 [L]
oder wie? Sollten dann links im Dokument besser alls absolut sein, oder? Vor allem Bilder...
Nein, die Upload-Frontend-Klasse brauchst Du jetzt immer, nur eine eventuelle existierende Backend-Klasse existiert noch nicht. Du kannst Dir unter "Frontend" ein Modul vorstellen, Du musst nicht unbedingt eine Klasse verwenden, eine Datei, die included wird oder eine Funktion könnte die aufgabe auch bewältigen.
OK. Also habe ich für alle Aktionen _eigene_ Frontend-Module/Klassen, nicht wir ich dachte _ein_ Frontend ;-) Das konnte ich mir schwer vorstellen.
OK. Also das Basismodul bindet dieses File-Upload Frontend-Modul ein, in diesem Modul regele ich sowohl die Ausgabe als auch das Auslesen der Daten. In dem Modul verwende ich halt smarty für die Ausgabe, mit der Logik(Parameter...GET/POST...) wie ich sie dann auch erwarte. Das heißt ich generiere das Forumular und sage ist POST und der Parameter soll "upfile" heißen. Dann bekommt der User das Formular, schickt das ab, es wird aufgrund des Requerst-Strings wieder dasselbe Modul geladen, jetzt muß ich am Anfang des Moduls merken, das Daten in den Umgebungsvariablen stehen, also z.B. if($_FILES['upfile']['name']) => übergebe die Daten über die definierte Schnittstelle an das Backend-Modul, also erstelle eine Instanz... der file_uplaod Klasse, welches die Aktionen ausführt, am Ende wird geprüft, ob Fehler aufgetreten sind und demnach wieder eine Ausgabe erzeugt.
Wo wird diese Klasse genau geladen?
Du meinst "included"? Vor der Verwendung, entweder werden alle Dateien mit allen Frontend-Klassen eingelesen, oder nur kondizional je nach Anfrage.
Wie sieht das denn praktisch aus? Die Datei-Upload Klasse wird nur geladen, wenn der Request an /file_upload.php geht. In welcher Form speichere ich diese Information? Oder gehört das noch zu den "Meta-Daten" zu jedem Modul die am Anfang aus einer txt-File ausgelesen werden? Denn irgendwie muß ich ja an die Prüfung if($request_file=="file_upload.php") include("file_upload_frontend.php")
Wo wird eine Instanz erstellt?
An der Stelle, wo klar ist, dass das Upload-Frontend verwendet werden soll.
Also innerhalb des Moduls, oder schon direkt nach dem includen ins basis-Script?
Aber auch mit der Basisklasse bin ich noch nicht so ganz warm. Was soll die Klasse denn genau machen außer ein paar feste Daten wie root_path und root_url zur Verfügung zu stellen?
|
Im Prinzip gar nichts... :-)
Aber sie läd immerhin alle notwendigen Module etc.
P.S.: Alles, was ich hier schreibe, ist mit meiner Einstellung behaftet, wie ich es realisieren würde. Aber Du darfst nie aus den Augen verlieren: Es gibt tausende Möglichkeiten, das zu realisieren.
Das ist mir bewußt, aber ich bin Dir sehr dankbar für Deine Anregungen, vermutlich muß ich das einmal komplett durchziehen, auch wenn das nicht alles auf meinen Mist gewachsen ist, aber dan bekomme ich wenigstens mal eine bessere Idee vom modularen Programmieren, und ab da entwickele ich eigene Vorlieben und eigene Lösungen.
Nochmals vielen Dank für Deine Geduld ;-)
Viele Grüße
Andreas
Hallo Andreas,
von der Basisklasse abgeleitet? Was bedeutet das schon wieder? Heißt die Frontendklasse Bilderupload wird von der Basisklase geladen(include) und instanziert(new...)? Oder erweiter mit extends...?
extends.
Also doch alles über ein Script. Dann läuftz das ganze also anders herum, das Basis-Script bindet das file-upload-Script ein, ich brauche als kein include("basis.modul.php") in jedem Script. OK. Und wie mache ich es das statt der URL mein basis-script aufgerufen wird? mod_rewrite? Wie habe ich mir das vorzustellen?
RewriteEngine On
RewriteRule ^(.*)$ /basis_script.php?params=$1 [L]oder wie? Sollten dann links im Dokument besser alls absolut sein, oder? Vor allem Bilder...
Ähm, das weiß ich auch noch nicht so genau, siehe [pref:t=32853&m=178830] ;-)
OK. Also das Basismodul bindet dieses File-Upload Frontend-Modul ein, in diesem Modul regele ich sowohl die Ausgabe als auch das Auslesen der Daten. In dem Modul verwende ich halt smarty für die Ausgabe, mit der Logik(Parameter...GET/POST...) wie ich sie dann auch erwarte. Das heißt ich generiere das Forumular und sage ist POST und der Parameter soll "upfile" heißen. Dann bekommt der User das Formular, schickt das ab, es wird aufgrund des Requerst-Strings wieder dasselbe Modul geladen, jetzt muß ich am Anfang des Moduls merken, das Daten in den Umgebungsvariablen stehen, also z.B. if($_FILES['upfile']['name']) => übergebe die Daten über die definierte Schnittstelle an das Backend-Modul, also erstelle eine Instanz... der file_uplaod Klasse, welches die Aktionen ausführt, am Ende wird geprüft, ob Fehler aufgetreten sind und demnach wieder eine Ausgabe erzeugt.
Genau.
Wie sieht das denn praktisch aus? Die Datei-Upload Klasse wird nur geladen, wenn der Request an /file_upload.php geht. In welcher Form speichere ich diese Information? Oder gehört das noch zu den "Meta-Daten" zu jedem Modul die am Anfang aus einer txt-File ausgelesen werden? Denn irgendwie muß ich ja an die Prüfung if($request_file=="file_upload.php") include("file_upload_frontend.php")
Du musst irgendwo diese Daten abspeichern, sei es fest verdrahtet, (schlechte Idee) einer Textdatei oder einer Datenbank (die flexibelste)
An der Stelle, wo klar ist, dass das Upload-Frontend verwendet werden soll.
Also innerhalb des Moduls, oder schon direkt nach dem includen ins basis-Script?
Die Klasse ist das Modul, klar? Ich habe ja gesagt, ein Modul _kann_ als Klasse realisiert werden, *muss* aber nicht.
Grüße,
Christian
Hallo!
So langsam bin ich an der konkreten Umsetzung, dieses Jahr mal Programmieren statt Weihnachten ;-)
*kleiner Scherz!*
Jedenfalls schwirren mir wieder 2 Problematiken im Kopf herum.
Thema 1: Datenbank-Zugriff.
Ich habe mich für PEAR enstchieden, das ja auch wunderbar portablen Code ermöglicht, aber eigentlich mehr auch nicht, die SQL-Statements stehen immer noch verstreut in allen Scripten. Jetzt frage ich mich ob sich das lohnt, die SQL-Abfragen über eine Klasse zu machen, also ich hatte das mal für einen Warenkorb so gemacht, so hatte ich kein SQL mehr im eigentlichen Code, sondern nur noch dineg wie $warenkorb -> getGesamtpreis(), $warenkorb -> getMwSt(), und in der Methode stand dann die entsprechende SQL-Abfrage. Die Frage die ich mir jetzt stelle - lohnt sich das? Was hätte ich für einen Vorteil? Wenn sich was ändert könnte ich das in der Klasse machen und müßte nicht in den Code, aber ändern müßte ich vermutlich auch nicht mehr wenn ich das ohne extra Klasse mache.
2. Problem, wie soll die Verzeichnisstruktur aussehen?
Bisher habe ich im Prinzip immer sowas gehabt:
/home/www/daten/
/home/www/webseite/
/home/www/webseite/images/
DOC-ROOT des Apachen wäre hier "/home/www/webseite/" , da lag dann die index.php drin, udn der Rest drum, herum, Script die ich nicht per HTTP brauchte, also reine include-Dateien habe ich in "/home/www/daten/" für HTTP unerreichbar gespeichert. So, jetzt habe ich ein bisschen überlegt, und die ganze Zeit im Hinterkopf, dass ich ja Plugins in mein Programm einbinden können will, oder auch weglassen kann. Wirklich gut gelöst ist das IMHO bei moregroupware(.org):
(Das Modul "contact" als Beispiel)
<img src="http://moregroupware.sourceforge.net/docs/moduletree.gif" border="0" alt="">
MGW hat halt seien Standardbibliothek die überall eingebunden werden kann. Wenn das Modul jetzt mehr braucht gibt es in einem Unterverzeichnes den Ordner inc. genau so wíe media für spezielle Bilder, und natürlich Templates und LANG-Files. Die Struktur finde ich schon gar nicht schlecht.
Aber erstmal die Frage, was ist mit den Rechten? Ich will ja nicht das alle Leute sich meine inc... Files angucken können. OK, die kann per .htaccess durch PHP schicken oder besser direkt .inc.php nennen nur sind die dann nicht mehr unerreichbar, wie ich das bisher immer hatte. Was könnte man machen? OK, eine .htaccess mit einem Zugangsschutz und ungültigem Passwort und die Rechte für die Scripte auf 600. Was könnte mir hier jetzt noch passieren?
Ich will die Dateien eines Plugins lieber nicht über das gesamte Dateisystem verteilen, daher finde ich das sehr gut wenn die Dateien so zusammenliegen, um ein Plugin einfach hinzufügen und entfernen zu können.
Was mich noch große Probleme bereitet ist dei Trennung von "Modul" und "Plugin". Wenn ich mal so überlege zum upload-Modul. Da hatten wir ein Backend-Modul und ein Frontend-Modul, aber wie brauche ich das in der Praxis? Eigentlich ist der Upload-Dialog z.B. einfach in einen Lieferantenfragebogen eingebettet. Der Lieferantenfragebogen-Generator war ja ein komplettes Plugin, halt eine Erweiterung des Basisprogramms, die nicht immer vorhanden ist. Dieses Plugin besteht dann aus verschiedenen Template und LANG-Files, aus verschiedenen Scripten, oder besser aus einem Script mit mehreren conditionalen includes, eben unter anderem mit dem Upload Front- und Backend. Die Frage ist ob das hier eigenständige Module sein sollten, oder ob diese mit den anderen Formularfeldern nicht besser ein komplettes Lieferantenfragebogen-Frontend und - Backend eingebettet werden.
Auch fraglich ist, wenn ich Upload - Felder in mehrern Formularen verwende, sollte ich dann lieber doch reine Upload-Frontend und -Backend draus machen, die sich halt auch in Formulare einbetten lassen, und die dann global allen Formularen zu Verfügung stehen?
Dann würde ich vielleicht ein extra Verzeichnis "includes/modules/" machen, in das ich nur solche Module wie das upload Front- und Backend packe, dann brauche ich am besten hier noch ein Unterverzeichnis für die einzelnden Templates und LANG-Files...
Die Plugins kommen dann in das Verzeicnis Plugins mit einer ähnlichen Struktur wie bei mgw.
Dann würde ich mir jetzt so eine Struktur vorstellen:
DOC-ROOT: /home/www/
/home/www/media/ (Bilder...)
/home/www/includes/(Module, Smarty, Config-Files...)
/home/www/plugins/ (Erweiterungen)
/home/www/.htaccess (mit rewrite-rule auf index.php)
/home/www/index.php (Basismodul, läd alles notwendige und leitet den Request weiter)
/home/www/styles.css
/home/www/...
So hatte ich mir das bisher vorgestellt. Nur in dieser Konstellation ist z.B. mein DB-Passort nicht sicher, oder ist das doch hinreichend sicher durch HTTP DIGEST AUTHENTIFICATION(require nicht vorhandenen User) und Datei-Rechte(PHP/zu parsende Flat-Files) auf 600 und Verzeichnisse auf 710.
Naja irgendwie habe ich da ein ungutes Gefühl. Was sagt Ihr dazu?
Viele Grüße
Andreas
Hallo!
weil mir solangsam der Schädel platzt, muss ich nun einfach mal in die Runde frage und ein paar Anregungen und Meinungen einholen.
Ich sitze zur Zeit an ähnlichen Problemen, und hatte dazu vor einigen Tagen einen recht fruchtbaren Thread gestartet: http://forum.de.selfhtml.org/archiv/2002/12/31778/
Diese Klassen sollen nun erstmal so weit wie möglich eigenständige Module sein, die zwar teilweise auf andere Klassen angewiesen sind, aber soweit möglich auch ohne diese auskommen.
Aber meiner Meinung nach ist die Modularität das genaue Gegenteil. Ein Modul soll ganz klar definierte Schnittstellen haben. Das Modul soll sich nicht alles möglicsh alleien beschaffen, sondern sich alle Daten aus anderen Modulen hoolen, oder die Daten sollen von anderen Modulen übergeben werden. Die Schnittstelel bleibt dann immer gleich, und Du kannst um das Modul selbstverändern, ohne das das Auswirkungen auf andere Teile des Programms hat. Umgekehrt kannst Du einfach die Umgebung verändern, z.B. von MySQL auf postgreSQL, wofür Du nur das DB-Modul anpassen mußt, aber keines der anderen Module, da die alle nur über das DB-Modul mit der Datenbank kommunizieren.
ein beispiel, es gibt eine fileUpload-Klasse, die hat die Aufgabe eine Datei die per POST hochgeladen wurde in ein bestimmtes Verzeichnis zu verschieben. Nun gibts verschiedene Filter und Regeln, die man definieren kann um zu entscheide wird die Datei akzeptiert oder nicht.
So weit so gut, nun hab ich entschieden diese um eine Klasse errorReporting zu erweitern, welche Fehlermeldungen und Ereignismeldungen verwaltet. Weiter gibts eine Klasse die Beispielsweise Thumbgrafiken erzeugen kann.Meine erste Idee war folgende. Die errorReporting-Klasse als Basisklasse fast aller Klassen zu verwenden, da Fehler überall auftreten können, die thumbnails selbst sind hingegen nicht so elementar für meine fileUpload-Klasse, deswegen erzeuge ich nach Bedarf eine Instanz davon.
Die Idee halte ich nicht für gut. Die Error-Klasse sollte ein eigenes Modul sein, welches Du in den anderen Modulen verwenden kannst, oder auch nicht. Ich würde z.B. ein Upload-Modul schreiben, darin steht eien Klasse, der bei einem Uplaod die Daten übergeben werden, also Temp-Name, Name, gewünschter Speicherpfad, gewünschter Name, zu erwartender Typ(z.B. Bild)...
Diese Klasse hat dann auch eine Mothode checkFile().
Bevor die Datei gespeichert wird, wird mit checkFile("Bild") geprüft, ob es sich bei der temporären Datei tatsächlich z.B. um eine gültige Bild-Datei handelt. Wenn dem so ist dann kannst Du die Datei kopieren, umbenennen...
Wenn dem nicht so ist, dann rufst Du das Error-Modul auf, welches eine Fehlermeldung produziert und/oder loggt.
Ich würde in das Modul vielleicht auch für jeden Typ eine extra Methode schreiben, ich habe z.B. auch Excel-Dateien, das würde ich ganz anders prüfen als eine JPG-Datei.
class fileUpload extends errorReporting {
function createThumb() {
$this->createThumb = new thumbnail();
....
}
Wie gesagt, ich würde das anders machen, da das so auch unlogisch ist, und Module sollen ja logisch sein. Was hat das kopieren von Bildern in einem Error-Modul verloren?
Nun ist aber eigentlich auch so, das ja meine fileUpload-Klasse selbst nicht wirklich davon abhängig ist Fehlermeldungen speichern zu können. So mache ich sie jedoch abhängig davon. Wäre es vielleicht nicht sinnvoller auch die errorReporting-Klasse nur bei Bedarf zu Instanzieren?
Ja, da hänge ich auch noch irgendwie. Insgesamt sollte man IMHO nur die Module laden die man auch braucht - nur wie? Dafür braucht man dann wohl das Basismodul, welches immer geladen wird, also in alle Scripte per include() eingebunden wird, und welches dann entscheiden muß, welche Module geladen werden sollen. Nur in welcher Form soll man das steuern? Sicher müssen dann die Modul-Dateien mit include eingebunden werden, udn mit IFs kann man das ja auch prima steuern, nur woher bekommen die if-Bedingungen wiederum ihre Daten? Wenn ich jetzt z.B. einen File-Upload mache. Dann habe ich das HTML-Forumlar, welches per POST am besten an sich selbst geschickt wird. Woher weiß jetzt das Basis-Modul, das an dieser Stelle das File-Upload Modul benötigt wird? Bisher mache ich sowas(ohne Module) immer so, dass ich frage
if($_POST['submit']) {
// file upload CODE
}
Aber wie mache ich das jetzt mit dem Basis-Modul? Das kann iach mir nicht vorstellen. Vielleicht frage ich _jedesmal_ (duch einbinden der Basis-Klasse in alle Scripte) mit if($_FILE) und wenn das TRUE ist dann binde ich halt die file-upload Klasse ein. Aber das müßteman dann ja mit jedem einzelnen Modul machen. Gibt es da keine bessere Lösung?
Und nochwas, wann sollte man eine Klasse instanzieren? Am besten doch schon im Basis-Modul, nach dem Include, dann ein "$file = new fileUpload", nur dann hätte ich im Basismodul eine Variable definiert, die ich ja im Prinzip im uplaod-Modul wissen müßte, das ist ja wieder blöd. Also sollte das Uplaod modul aus der Klasse bestehen, und aus PHP-Anfweinungn die eine Instanz erstellen, und der Klasse dann die notwendigen Daten übergeben. Nur dann ist das mOdul ja wieder nicht so besonders modular, dann greife ich im Modul ja wieder direkt auf Umgebungsvariablen zu... wie macht man das denn besser?
Man bräuchte noch eine Möglichkeit, diesen Teil auch abzukapseln, also der Upload-Klasse über deren Schnittstelle die Daten zu übergeben. Aber wie?
Macht es Sinn in der Praxis, alle Klassen die man zwar brauchen könnte, jedoch nicht unbedingt benötigt in einer Klasse bei Bedarf zu Instanzieren? So überlegt könnte ich ja eigentlich fast alles so handhaben, da beinahe jede Klasse bis zu einem gewissen Punkt alleine klar kommt. Oder leidet die übersichtlichkeit und Transparenz irgendwann darunter?
Das würde ich sowieso machen, das wäre ja ein tierischer Overhead wenn man immer alles laden würde, nur wie man das in der Praxis mit PHP sauber macht ist mir nicht nicht wirklich klar. Oder könnte hier "::" helfen, also Methoden nutzen ohne Instanz?
Ich mache mir gerade megaviele Gedanken, wie ich Klassen so gestalten kann, die sie so eigentständig wie möglich funktionieren und welche Aufbau wirklich sinn macht. Vielleicht kann jemanden ein paar Tipps geben, der sich schon intensiver damit auseinandergesetzt hat, oder kennt ein Tutorial das nicht auf Einsteigerniveau liegt, davon gibts genug.
Das ist schwer, ich komme da auch nur schleppend weiter, das hört sich immer so klar und logisch an, was die Christians oder Sven zu dem Thema sagen, nur wenn ich danach da sitze und das umsetzen will stehe ich da und weiß nicht wo und wie ich ansetzen soll. Theoretisch habe ich es denke ich langsam verstanden, jetzt muß ich das nur noch in der Praxis umsetzen können, was nicht ganz so einfach ist. Was ich so langsam raushabe ist zumindest das DB-Modul und das Ausgabe Modul, hierfür bin ich dabei Smarty etwas zu erweiter, das ich hier auch mehrsprachige Templates einsetzen kann, und zwar der Art, dass ich nur je ein Template habe, und das Smarty für jede Sprache ein "kompiliertes" Template speichert, kompiliert heißt in diesem Zusammenhang das Script und das Template schon zusammensetzt damit das nicht bei jedem Seiten aufrufe immer wieder gemacht werden muß. Nur muß ich hierzu die Smarty-Klasse abändern, bzw. erweitern.
Grüße
Andreas
Hio Andreas,
Ich sitze zur Zeit an ähnlichen Problemen, und hatte dazu vor einigen Tagen einen recht fruchtbaren Thread gestartet: http://forum.de.selfhtml.org/archiv/2002/12/31778/
diesen Thread hab ich mir nun mal ein wenig durchgelesen.
Es sind sehr interessante Anregungen und Tipps dabei, wobei der "Übergang" von der Theorie in die Praxis trotzdem noch einmal eine Sache für sich ist ;)
Aber meiner Meinung nach ist die Modularität das genaue Gegenteil. Ein Modul soll ganz klar definierte Schnittstellen haben. Das Modul soll sich nicht alles möglicsh alleien beschaffen, sondern sich alle Daten aus anderen Modulen hoolen, oder die Daten sollen von anderen Modulen übergeben werden.
hm, ja und nein. Ich verstehe Module auch als eine Art "Stecksystem", vergleichsweise mit Lego ;) Aber ich bin der Meinung, ein Modul sollte eine klar definierte Aufgabe haben und diese eigenständig ausführen können. Z.b. die fileUpload-Klasse, sie soll Dateien vom tempörären Verzeichnis nach x verschieben. Zu entscheiden ob diese Datei nun zu gross oder falsches Format ist, ist alleinige Aufgabe dieser Klasse und keiner anderen. Wenn ich nun z.b. ein Thumbnail erzeugen möchte oder nach Viren checken möchte, dann komme ich in einen anderen Aufgabenbereich als die Kernaufgabe dieser Klasse. Dann benötige ich andere Klassen für diese Aufgabe und an dieser Stelle klar definierte Schnittstellen damit diese Klassen kommunizieren können.
Die Idee halte ich nicht für gut. Die Error-Klasse sollte ein eigenes Modul sein, welches Du in den anderen Modulen verwenden kannst, oder auch nicht.
Sehe ich nun auch so, wie gesagt, meine erste Idee war sie als Basisklasse zu verwenden, gerade weil Fehler überall auftreten können. Nun strebe ich eine andere Lösung an. Ich verpasse der fileUpload-Klasse eine Funktion, welche bei Bedarf eine Instanz von errorReprting erzeugt und mit dieser Kommuniziert.
z.b.
function setErrorMessage() {
if (isset($this->errorHandler)) $this->errorHanlder = newErrorReprting;
$this->errorHandler->setErrorMessage(10,"FILE_NOT_FOUND","Datei x.gif wurde nicht gefunden");
}
Meine aktuelle Überlegung ist, nun die wesentlichen Funktionien direkt in den scope der Klasse mit get_object_methods zu importieren,
aber so sicher bin ich da nicht.
Der Vorteil, sie nicht als Basisklasse sondern zu Instanzieren ist denke ich, ich kann mehrere errorReport-Instanzen mit verschiedenen Aufgaben erzeugen, anstatt nur _eine_ Fehlerbehandlung.
Ich würde in das Modul vielleicht auch für jeden Typ eine extra Methode schreiben, ich habe z.B. auch Excel-Dateien, das würde ich ganz anders prüfen als eine JPG-Datei.
hm, ist natürlich eine Überlegung wert, die Frage ist ob man das über eine Zwischenklasse macht oder nicht.
z.b.
fileUpload -> fileAnalyser -> excelFiles
oder so
class fileUpload extends errorReporting {
function createThumb() {
$this->createThumb = new thumbnail();
....
}Wie gesagt, ich würde das anders machen, da das so auch unlogisch ist, und Module sollen ja logisch sein. Was hat das kopieren von Bildern in einem Error-Modul verloren?
Würde ich aktuell auch, wobei ich das aber als fileUpload-Modul gesehen habe, welches ein Fehlermodul besitzt, den auch beim erzeugen von Thumbs können Fehler auftreten, z.b. "GIF NOT SUPPORTED"
Aber wie mache ich das jetzt mit dem Basis-Modul? Das kann iach mir nicht vorstellen. Vielleicht frage ich _jedesmal_ (duch einbinden der Basis-Klasse in alle Scripte) mit if($_FILE) und wenn das TRUE ist dann binde ich halt die file-upload Klasse ein. Aber das müßteman dann ja mit jedem einzelnen Modul machen. Gibt es da keine bessere Lösung?
Ich finde die Idee mit einem Basismodul als elementares Grundmuster erstmal nicht so gut, hab solche Vorschläge schon mehrfach gehört. Aber ein ich denke, letztendlich wird man kein System erstellen können, das jede erdenkliche Aufgabe lösen kann. Also wird man ein Problem in der Praxis angehen, indem man rund um seine Module programmiert, die vielleicht ja irgendwann viele Standardaufgaben automatisiert erfüllen.
Das würde ich sowieso machen, das wäre ja ein tierischer Overhead wenn man immer alles laden würde, nur wie man das in der Praxis mit PHP sauber macht ist mir nicht nicht wirklich klar. Oder könnte hier "::" helfen, also Methoden nutzen ohne Instanz?
Ich denke teilweise schon.
Ich mache mir gerade megaviele Gedanken, wie ich Klassen so gestalten kann, die sie so eigentständig wie möglich funktionieren und welche Aufbau wirklich sinn macht. Vielleicht kann jemanden ein paar Tipps geben, der sich schon intensiver damit auseinandergesetzt hat, oder kennt ein Tutorial das nicht auf Einsteigerniveau liegt, davon gibts genug.
Das ist schwer, ich komme da auch nur schleppend weiter, das hört sich immer so klar und logisch an, was die Christians oder Sven zu dem Thema sagen, nur wenn ich danach da sitze und das umsetzen will stehe ich da und weiß nicht wo und wie ich ansetzen soll. Theoretisch habe ich es denke ich langsam verstanden, jetzt muß ich das nur noch in der Praxis umsetzen können, was nicht ganz so einfach ist.
Hehe ;) das kenne ich. In der Theorie sieht vieles immer sehr gut aus, in der Praxis dann "anders".
Ich versuche mir momentan damit zu helfen, indem ich "Kernaufgaben" sehe. Z.b. hinterfrage ich bei jedem Feature der fileUpload-Klasse ob dies wirklich zur Kernaufgabe gehört oder nicht, z.b. thumbnails, klares nein, also überlege ich in welchen Kernaufgabenbereich gehört dieses Problem und welche Klasse (Modul) sollte dies lösen.
Mein Kopf raucht bestimmt genauso wie deiner ;)
gl & hf
Thorsten
Hallo!
function setErrorMessage() {
if (isset($this->errorHandler)) $this->errorHanlder = newErrorReprting;
$this->errorHandler->setErrorMessage(10,"FILE_NOT_FOUND","Datei x.gif wurde nicht gefunden");
}
Meine aktuelle Überlegung ist, nun die wesentlichen Funktionien direkt in den scope der Klasse mit get_object_methods zu importieren,
aber so sicher bin ich da nicht.
wieso? Was sind die wesentlichen Funktionen?
Der Vorteil, sie nicht als Basisklasse sondern zu Instanzieren ist denke ich, ich kann mehrere errorReport-Instanzen mit verschiedenen Aufgaben erzeugen, anstatt nur _eine_ Fehlerbehandlung.
ich dachte Du erzeugst eine Instanz für jede neue Fehlermeldung?! Also ich würde jeden Fehler an die Klasse als neue Instanz übergeben, und je nachdem ragieren. Am Ende alle Fehler(Instanzen) ausgeben, loggen...
hm, ist natürlich eine Überlegung wert, die Frage ist ob man das über eine Zwischenklasse macht oder nicht.
z.b.
fileUpload -> fileAnalyser -> excelFiles
oder so
Ich meien eine Klasse, und innerhalb der Klasse verschiedene Methoden, einmal
checkFile() die verwendet dann zum checken entweder checkExcel() oder checkJPG()...
alles innerhalb einer Klasse.
Würde ich aktuell auch, wobei ich das aber als fileUpload-Modul gesehen habe, welches ein Fehlermodul besitzt, den auch beim erzeugen von Thumbs können Fehler auftreten, z.b. "GIF NOT SUPPORTED"
Klar! Du schreibst dann jedesmal wenn Du eine Thumb erzeugst, kopierst oder checkst, in die einzelnen Methoden if(error) new error_class(10,bla,blub)
So dass Du für jeden Fehler eien eigen Instanz erhälst, so würde ich das machen, habe aber selbst noch kein wirklich gutes Konzept muß ich dazu sagen ;-)
Das würde ich sowieso machen, das wäre ja ein tierischer Overhead wenn man immer alles laden würde, nur wie man das in der Praxis mit PHP sauber macht ist mir nicht nicht wirklich klar. Oder könnte hier "::" helfen, also Methoden nutzen ohne Instanz?
Ich denke teilweise schon.
Wo denn z.B.? Ich bin mir noch nicht mal so sicher wann ich eien Instanz bracueh und wann nicht. Eigentlich brache ich immer eine Instanz, denn ohne kann ich ja kein $this... verwenden, also kann ich nur die Funktion an sich verwenden, oder?
Mein Kopf raucht bestimmt genauso wie deiner ;)
ich wünsche es Dir nicht ;-)
Grüße
Andreas
Hio Andreas,
Meine aktuelle Überlegung ist, nun die wesentlichen Funktionien direkt in den scope der Klasse mit get_object_methods zu importieren,
aber so sicher bin ich da nicht.
wieso? Was sind die wesentlichen Funktionen?
hm, deswegen war ich mir wahrscheinlich nicht sicher ;)
ich dachte Du erzeugst eine Instanz für jede neue Fehlermeldung?! Also ich würde jeden Fehler an die Klasse als neue Instanz übergeben, und je nachdem ragieren. Am Ende alle Fehler(Instanzen) ausgeben, loggen...
So wars eigentlich nicht gedacht. Nich für jede einzelne Fehlermeldung, sondern evtl. für verschiedene Arten der Fehlermeldungen. Z.b. Reports und Errors, wobei Reports allgemeine Hinweise enthalten können und Errors nur tatsächliche Fehler. Aber eine Instanz von Error hätte dann eine Liste aller Fehlermeldunge, die ich am Ende ausgeben oder auch in eine Datei schreiben kann.
Für jeden Fehler eine neue Instanz zu Erzeugen find ich nicht so gut, dürfte problematisch bei der Handhabung werden. Wie komme ich dann am Ende an _alle_ Fehlermeldungen ran. Für mich ist _eine_ Instanz Error einfach für alle auftretenden Fehler zuständig und behandelt diese am Ende nach Wunsch, z.b. in eine Datei schreiben.
checkFile() die verwendet dann zum checken entweder checkExcel() oder checkJPG()...
alles innerhalb einer Klasse.
jup, da dürften dynamische Funktionen interesant werden, wobei man bei einer allgemein gültigen Schnittstelle bleiben kann.
if ($fileType = "EXCEL") $checkFile = "checkFile";
if ($fileType = "JPG") $checkFile = "checkJPG";
checkFile("xxx");
So dass Du für jeden Fehler eien eigen Instanz erhälst, so würde ich das machen, habe aber selbst noch kein wirklich gutes Konzept muß ich dazu sagen ;-)
Hatte ich eigentlich nicht vor, s.o.
Eine neue Instanz nur falls ich andere Meldungen haben will.
Mein Konzept ist, das ich eine Instanz erzeuge, bei der ich das Format einstellen, das Ausgabemedium, sowie welche Fehlermeldungen tatsächlich erfasst werden. Meine Klassen ansich geben jeden Fehler den sie erkennen an errorReprting weiter, diese entscheidet nun ob sie den Fehler nimmt oder nicht.
Deswegen auch die Überlegung, Methoden in den Scope der Klasse zu holen. Wenn ich z.b. das Format festlegen will, müsste ich das ja immer über diese Instanz machen. Was ich dann ausserhalb der Klasse nicht nach
$test = &new fileUpload;
$test->enableErrorLogging();
$test->setErrorFormat("%errCode %errMsg %errDesc %ip %datetime");
machen können. Wobei mir das lieber wäre. Da ich ja mit einem fileUpload-Modul arbeite, welches durch errorReporting die möglich bekommen soll, Fehler zu handeln.
Sie muss daher nicht ultraflexibel mit allen Fehlermeldungen umgehen können, sondern es reicht wenn man Fehler erfassen kann und wenn man Reports (also z.b. Upload von xxx.gif erfolgreich) erfassen kann.
Sie soll vielmehr bei Bedarf sich die wichtigstens Funktionen von errorReporting importieren, also erweitert sich das Modul fileUpload durch das Modul errorReporting, wenn die Aufgabenstellung es erfordert, und das nach festdefinierten, auf fileUpload zugeschnittenen Bedürfnissen.
Das würde ich sowieso machen, das wäre ja ein tierischer Overhead wenn man immer alles laden würde, nur wie man das in der Praxis mit PHP sauber macht ist mir nicht nicht wirklich klar. Oder könnte hier "::" helfen, also Methoden nutzen ohne Instanz?
Ich denke teilweise schon.
Wo denn z.B.? Ich bin mir noch nicht mal so sicher wann ich eien Instanz bracueh und wann nicht. Eigentlich brache ich immer eine Instanz, denn ohne kann ich ja kein $this... verwenden, also kann ich nur die Funktion an sich verwenden, oder?
Ja, du hast keinen Zugriff auf irgendwelche Objektvariablen, da es ja keine Instanz gibt. Sofern du aber auf diese nicht angewiesen bist, brauchst du auch keine Instanz. Z.b. um eine "veraltete" error.log-Datei zu löschen über eine Funktion deleteLogfile($filename = ""), müsstest du nicht unbedingt eine Instanz erzeugen.
Mein Kopf raucht bestimmt genauso wie deiner ;)
ich wünsche es Dir nicht ;-)
danke, hat aber nichts geholfen ;)
gl & hf
Thorsten
P.S.
Ich spiele momentan mit der Überlegung eine kleine Seite diesbezüglich aufzubauen. D.h. ob ich mir z.b. die fileUpload-Klasse nehme und diese von Grund auf als eine quasi Workshop vorstelle. D.h. welche Vorüberlegungen hatte ich bis hin zur Realisierung und den damit verbundenen Problemen und das ganze dann mit einem kleinen Diskussionforum unterlege, also einen kleinen interaktives Workshop. Leider ist das nicht mal so von heut auf morgen umzusetzen und zeitlich erstmal nicht drin.