Komplettes Projekt in OOP
Chris
- php
Hello out there.
Ich habe vor mein neues Projekt komplett objekorientiert zu halten.
Allerdings stoße ich dort auf Probleme.
Urpsprünglich wollte ich zum Beispiel eine Datenbankklasse haben die sämtliche Datenbank-Methoden enthalten sollte erstellen.
Unter Verwendung von MySQLi, sollen auch prepared Statements dynamisch erstellt werden können.
Nun. prepare() braucht aber zum Beispiel das erstellte Datenbankobjekt.
Also war mir schonmal klar, die erweiterten DB-Funktionen und die Haupt-DB-Funktionen(connect, close z.B.) können nicht in einer Klasse stehen.
Da aber alle Klassen die DB-Methoden haben müssen, sprich erben werden und PHP nur eine einzige Vererbung pro Klasse _direkt_ zulässt, habe ich mich dazu entschlossen eine "Main_Class" zu erstellen die in jede Klasse eingebunden wird.
Das ganze sieht also so aus:
KLASSE erbt von Main_Class erbt von "weitere_DB_Funktionen" erbt von "Haupt-DB-Funktionen"
Allerdings finde ich das extrem umständlich und unsauber.
Vor allem weiß ich garnicht mehr wo das DB-Objekt erstellt werden soll.
Ich nehme man in der index.php werde ich das oben tun oder in der Main_Class.
Desweiteren müssen alle "Standard-Funktionen", sprich Funktionen die ich mir erstellen werde die man öfters mal braucht wie z.B. "requests2array", "timestamp2date" - die Namen sind wohl selbsterklärend, in der Main_Class stehen.
Aus der vermeintlich durch OOP erwünschter Ordnung entsteht meiner Ansicht nach ein Chaos und mir fällt es schwer das Projekt gerecht zu planen.
Ich hoffe ihr könnt mir Ratschläge, Beispiele, Hilfe und vielleicht ein wenig Motivation geben, das ganze so "modern" umzusetzen. Übersichtlich und dennoch möglichst performant.
Liebe Grüße,
Chris
Hello Chris,
Ich habe vor mein neues Projekt komplett objekorientiert zu halten.
Du weißt doch, dass ich es ablehne, ein Projet nur um der OOP selbst Willen "rein objektorientiert" aufzubauen.
Außerdem geht das gar nicht.
An irgend einer Stelle muss man immer die Basisdefinitionen durchführen. Und wenn man die nicht kennt, kann man nichts darauf aufbauen. Echte Objektorientierung baut immer auf gültigen Basisdefinitionen auf. Darum gibt es auch bisnheute keine echte Objektorientierung, weil es niemanden gibt, der für die dieser Objektorientierung zugrundeliegenden Definitionen haften will.
*ätsch*
Liebe Grüße aus Syburg
Tom vom Berg
Du weißt doch, dass ich es ablehne, ein Projet nur um der OOP selbst Willen "rein objektorientiert" aufzubauen.
Außerdem geht das gar nicht.
An irgend einer Stelle muss man immer die Basisdefinitionen durchführen. Und wenn man die nicht kennt, kann man nichts darauf aufbauen. Echte Objektorientierung baut immer auf gültigen Basisdefinitionen auf. Darum gibt es auch bisnheute keine echte Objektorientierung, weil es niemanden gibt, der für die dieser Objektorientierung zugrundeliegenden Definitionen haften will.
Hallo Tom,
dies ist mir bewusst. Ich meinte damit auch eher alles wichtige, größere, grundlegende an Funktionen und Features (Datenbankverwaltung, PM-System, Kontaktformular, Gästebuch all sowas..).
lg
Chris
Ahoi,
Hello Chris,
»» Ich habe vor mein neues Projekt komplett objekorientiert zu halten.
Du weißt doch, dass ich es ablehne, ein Projet nur um der OOP selbst Willen "rein objektorientiert" aufzubauen.
Außerdem geht das gar nicht.
An irgend einer Stelle muss man immer die Basisdefinitionen durchführen. Und wenn man die nicht kennt, kann man nichts darauf aufbauen. Echte Objektorientierung baut immer auf gültigen Basisdefinitionen auf. Darum gibt es auch bisnheute keine echte Objektorientierung, weil es niemanden gibt, der für die dieser Objektorientierung zugrundeliegenden Definitionen haften will.
*ätsch*
Was meinst Du damit?
http://framework.zend.com/manual/de/introduction.html
"Zend Framework (ZF) ist ein Open Source Framework für die Entwicklung von Web Anwendungen und Services mit PHP 5. ZF wurde durch Verwendung von 100% Objektorientiertem Code implementiert."
Dank und Gruß,
Vielleiche versteh ich das Problem nicht, aber ...
Nun. prepare() braucht aber zum Beispiel das erstellte Datenbankobjekt.
Also war mir schonmal klar, die erweiterten DB-Funktionen und die Haupt-DB-Funktionen(connect, close z.B.) können nicht in einer Klasse stehen.
Warum nicht?
KLASSE erbt von Main_Class erbt von "weitere_DB_Funktionen" erbt von "Haupt-DB-Funktionen"
Warum muss jede Klasse alles erben? Kann eine Klasse nicht eine andere verwenden, ohne von ihr zu erben?
Desweiteren müssen alle "Standard-Funktionen", sprich Funktionen die ich mir erstellen werde die man öfters mal braucht wie z.B. "requests2array", "timestamp2date" - die Namen sind wohl selbsterklärend, in der Main_Class stehen.
Selbe Frage, warum müssen sie das?
Ich kenne zwar die oo-Möglichkeiten von PHP noch nicht so richtig, aber ich programmiere in einer anderen, rein objektorientierten Sprache und habe all diese Probleme nicht.
Hallo,
Hello out there.
Urpsprünglich wollte ich zum Beispiel eine Datenbankklasse haben die sämtliche Datenbank-Methoden enthalten sollte erstellen.
Unter Verwendung von MySQLi, sollen auch prepared Statements dynamisch erstellt werden können.
Hast du dir PDO (PHP Data Objects, http://www.php.net/manual/en/book.pdo.php) mal angesehen?
Gruß
Stareagle
Hast du dir PDO (PHP Data Objects, http://www.php.net/manual/en/book.pdo.php) mal angesehen?
Ja ich möchte allerdings mit MySQLi arbeiten ;)
Danke trotzdem.
Ahoi,
»» Hast du dir PDO (PHP Data Objects, http://www.php.net/manual/en/book.pdo.php) mal angesehen?
Ja ich möchte allerdings mit MySQLi arbeiten ;)
Danke trotzdem.
http://framework.zend.com/manual/en/zend.db.html#zend.db.adapter.adapter-notes.mysqli verbindet beides.
Dank und Gruß,
echo $begrüßung;
Urpsprünglich wollte ich zum Beispiel eine Datenbankklasse haben die sämtliche Datenbank-Methoden enthalten sollte erstellen.
Das und auch der nachfolgende Text liest sich so, als ob du die eierlegende Wollmichsau programmieren willst. Doch mit all den Funktionen steigt auch die Komplexität des Systems und damit der Wartungsaufwand.
Hast du dir zunächst erst einmal Gedanken darüber gemacht, welche(s) konkrete(n) Problem(e) du damit zu lösen versuchst?
Unter Verwendung von MySQLi, sollen auch prepared Statements dynamisch erstellt werden können.
Wenn du sowieso das Statement dynamisch und noch dazu bei jedem Scriptaufruf erneut zusammenbaust ist als Vorteil von Prepared Statements nur noch das Nichtbehandelnmüssen der Werte übrig geblieben. Das erkaufst du dir auch noch durch recht umständliches Handling der Parameter- und Result-Bindung. Es ist dann möglicherweise sogar weniger aufwendig und performanter, das Statement auf herkömmliche Weise zusammenzubauen, inklusive händischer Maskierung und Quotierung. Hinzu kommt noch, dass du das Ergebnis-an-Variable-Binden gar nicht gescheit nutzen kannst, wenn du das Resultset als Ganzes den Abnehmern zur Verfügung stellen willst.
Nun. prepare() braucht aber zum Beispiel das erstellte Datenbankobjekt.
Das kannst du dir ja mit Hilfe des Singleton-Pattern besorgen.
Also war mir schonmal klar, die erweiterten DB-Funktionen und die Haupt-DB-Funktionen(connect, close z.B.) können nicht in einer Klasse stehen.
Connect und Close muss die Hauptklasse von selbst machen. Dies sollte man nicht den Anwendern (sprich: anderen Programmteilen) überlassen, denn die wissen ja gar nicht, wann der beste Zeitpunkt zum Öffnen und Schließen ist. Es ist ja nicht sinnvoll, dass das mehrfach im Script passiert. - Und damit hast du gleich noch die nächste Frage: Wann ist der beste Zeitpunkt für ein Close? Im Grunde genommen kannst du nur darauf verzichten. Die DB-Klasse weiß nicht ob noch weitere Anforderungen kommen und die Anforderer wissen auch nicht, was nach ihnen noch passieren wird. Die DB-Klasse weiß lediglich welches die erste Anforderung ist und kann dafür die Verbindung eröffnen. Weitere Anforderer bekommen dann diese offene Verbindung.
Wobei man das ganze System am besten als Lazy Connect aufbaut. Ein Bedarfsträger kann zwar die DB-Klassen-Instanz anfordern, muss aber nicht zwangsläufig Funktionen verwenden, die eine DB-Verbindung brauchen. Deswegen muss nur jede Funktion, die eine Verbindung braucht, prüfen, ob diese schon offen ist, ansonsten sie eröffnen. Schau dir mal an, wie das im Zend Framwork gelöst ist.
Da aber alle Klassen die DB-Methoden haben müssen, sprich erben werden und PHP nur eine einzige Vererbung pro Klasse _direkt_ zulässt, habe ich mich dazu entschlossen eine "Main_Class" zu erstellen die in jede Klasse eingebunden wird.
Zur Not gäbe es immer noch das Decorator-Pattern. Aber das würde ich jetzt nicht als Lösung deines Problems ansehen sondern eher eine bessere Strukturierung und Arbeitsteilung.
Vor allem weiß ich garnicht mehr wo das DB-Objekt erstellt werden soll.
Die Geschäftslogik muss eigentlich gar nicht wissen, dass es da eine DB-Klasse gibt. Sie sollte nur wissen, wie sie an bestimmte Daten kommt. Sie sollte sich idealerweise auch gar nicht um das Zusammenbauen der SQL-Statements und dem Hantieren mit der Datenbank befassen müssen. Ein Funktionsaufruf, der ein Ergebnis liefert - fertig. Der Rest ist Blackbox.
Klappt man den Deckel der Blackbox auf, sieht man zunächst konkrete Datenlieferanten, die aus den Eingabeparametern die Anfrage zurechtbauen und ein Ergebnis zurückliefern. Schaut man tiefer, sieht man, dass die sich bei grundlegender benötigter Funktionalität bei einer gemeinsamen Basisklasse bedienen oder andere Klassen damit beauftragen (auch die DB-Hauptklasse).
Desweiteren müssen alle "Standard-Funktionen", sprich Funktionen die ich mir erstellen werde die man öfters mal braucht wie z.B. "requests2array", "timestamp2date" - die Namen sind wohl selbsterklärend, in der Main_Class stehen.
Wo auch immer sie am besten aufgehoben sind. Vielleicht ist es sinnvoll, eine Helper-Klasse zu erstellen, die eine Reihe von statischen Funktionen bereithält, die einfach so aufgerufen werden können, sprich: keine DB-Funktionalität benötigen.
Übersichtlich und dennoch möglichst performant.
Je weniger Code verwendet wird, desto näher kommt man im Allgemeinen an beide Ziele.
echo "$verabschiedung $name";
Hallo dedlfix,
vielen Dank für diese ausführliche Antwort. Sehr kompetent.
Allerdings ist es so gut geschrieben das ich 3 Kaffees brauche, 10 Std Schlaf und eine Kopfmassage damit ich das alles auffassen kann.
Könntest du mir das irgendwie, vllt ein bisschen weniger komplex als Pfeildiagramm darstellen?
bei mir ist ja zur zeit:
jede Klasse extends main Klasse extends datenbankklasse mit funktionen extends datenbankklasse mit connect,close funktion
Liebe Grüße,
Chris
Moin!
bei mir ist ja zur zeit:
jede Klasse extends main Klasse extends datenbankklasse mit funktionen extends datenbankklasse mit connect,close funktion
Ich denke, dein bisheriger Denkfehler bzw. das (noch) Nichtverständnis von OOP ist, auf welche unterschiedlichen Arten Objekte miteinander interagieren können.
Die eine denkbare Methode hast du schon herausgefunden: Vererbung. Das ist eine Möglichkeit, und PHP erlaubt zum Glück keine Mehrfachvererbung (damit kann man sich die schönsten Gehirnknoten basteln - und Gehirnknoten sind bei der Softwareentwicklung nie gut).
Was PHP 5 außer der Vererbung mittels EXTENDS erlaubt, und sogar mehrfach, ist das Implementieren von Interfaces. Das allerdings brächte dir keinen unmittelbaren Vorteil, denn eine Interface-Definition legt nur fest, welche Public-Methoden eine Klasse alle haben soll, sie legt aber nicht fest, was diese Methoden real tun, sie definieren nur, welche Parameter eine Methode erwartet. Das ist für den Entwickler also nur eine Gedächtnisstütze, damit er keine zu implementierende Methode vergisst.
Die viel spannendere Interaktion zwischen Objekten ist aber, wenn die Methode eines Objekts als Parameter ein anderes Objekt übergeben bekommt. Du kannst also beispielsweise den Zugang zur Datenbank als Instanz der MySQLi-Klasse realisieren, und dieses Objekt jeder Klasse mit übergeben, die Datenbankzugriff realisieren muss. Und zwar eben nicht als Vererbung, sondern als Parameter beispielsweise dem Konstruktor des Objekts. Wenn der Konstruktor sich dieses Objekt in einer protected-Variablen speichert, können alle weiteren Methoden auf die Datenbank zugreifen, indem sie das gespeicherte Objekt verwenden.
Und da kommen dann die sogenannten Design-Patterns recht schnell ins Spiel: Es wäre sowohl Verschwendung an Speicherplatz, als auch belastend für die Datenbank, wenn ein einziges Skript für seine vielleicht zehn datenbankzugreifenden Objekte auch zehn Datenbank-Connections benutzen würde. Deshalb möchte man vermeiden, dass sich das Objekt für den direkten Datenbank-Kontakt unendlich dupliziert, und realisiert dies, indem man dieses Objekt mit dem Singleton-Pattern erstellt.
Aber Vorsicht: Das Singleton-Pattern verleitet sehr leicht zum Mißbrauch. Im Prinzip ist dieses Pattern die Reinkarnation von globalen Variablen mit anderen Mitteln. Für den Datenbankzugriff ist es vermutlich meistens gerechtfertigt, in vielen anderen Fällen eher nicht.
Toms Anmerkung hat allerdings ihre Berechtigung: Man kann OOP auch übertreiben. Und vor allem bei OOP-unerfahrenen Entwicklern überwiegt erstmal die Faszination, alles rein mit OOP machen zu wollen, und der Realismus tritt in den Hintergrund.
Die Mischung macht es. Wenn du bislang prozedural programmiert hast (und hoffentlich vernünftig), dann wäre ein guter Zwischenschritt, die grundlegende Skript-Logik erst einmal weiterhin so laufen zu lassen, aber anstelle der diversen Funktionen Objekte einzuführen, die begrenzte Aufgaben erledigen. Das Zusammenführen der Objekte geschieht dann im OOP-losen "Hauptprogrammteil" des Skripts.
- Sven Rautenberg
echo $begrüßung;
Könntest du mir das irgendwie, vllt ein bisschen weniger komplex als Pfeildiagramm darstellen?
Na, mal sehen.
jede Klasse extends main Klasse extends datenbankklasse mit funktionen extends datenbankklasse mit connect,close funktion
Das ergibt am Ende, dass jede Instanz einer spezialisierten Klasse das komplette Erbe mit sich herumführt. Wenn du 3 Objekte erstellst, hast du auch 3 mal Datenbankverwaltung. Du brauchst aber nur eine, also steck die grundlegende Datenbankfunktionalität in eine eigenständige Klasse. Von der soll es nur eine einzige Instanz geben (vorausgesetzt du kommunizierst nur mit einem einzigen DMBS). Entweder übergibst du diese Instanz jedem Konstruktor, musst sie dafür aber auf Vorrat erzeugen. Oder du bedienst dich des Singleton-Patterns, das erst dann losläuft, wenn es gebraucht wird.
Wahrscheinlich denkst du grad nur daran, das Datenbankhandling, das sich früher im gesamten Script verteilt hatte, zu separieren. Vermutlich willst du aber noch wesentliche Bestandteile im Hauptprogramm lassen (Erstellung von Statements, Routinearbeiten beim Ergebnislesen, wasweißich). Ich habe in meiner ersten Antwort schon Aspekte einer weiteren Spezialisierung ins Spiel gebracht. Ich erachte es momentan als ideal[1], wenn das Hauptprogramm überhaupt nichts mehr mit der Beschaffung oder der Formulierung der Anfrage nach den Daten zu tun hat. Zwischen den grundlegenden und allgemein verwendbaren Funktionen des DBMS-Handlings ist also noch eine Schicht eingefügt, die die speziellen Anforderungen abwickelt, indem sie das Statement formuliert und die Daten holt. Das Hauptprogramm wird also entlastet und diese Datenschicht besorgt die Daten. Sie kann bei Bedarf auch die Daten woanders besorgen, ohne dass das Hauptprogramm dazu angepasst werden muss.
Ein Pfeildiagramm ist nun nicht entstanden, aber das wird auch nicht benötigt. Ich möchte dich nicht darin bestärken ein Klassenkonstrukt aufzubauen sondern darin, die Funktionalität zu beleuchten und anhand dieser die programmiertechnischen Einheiten zu bilden.
[1] Abgesehen davon, dass es Muster wie das MVC gibt, die das Ganze zwar noch flexibler dafür aber auch noch komplexer machen. Die Flexibilität eines Systems ist umgekehrt proportional zu seiner Komplexität.
echo "$verabschiedung $name";
Ahoi,
Zwischen den grundlegenden und allgemein verwendbaren Funktionen des DBMS-Handlings ist also noch eine Schicht eingefügt, die die speziellen Anforderungen abwickelt, indem sie das Statement formuliert und die Daten holt. Das Hauptprogramm wird also entlastet und diese Datenschicht besorgt die Daten. Sie kann bei Bedarf auch die Daten woanders besorgen, ohne dass das Hauptprogramm dazu angepasst werden muss.
Der Quickstart des Zendframeworks zeigt hierzu ein Beispiel, was ich in dem Zusammenhang als recht hilfreich/vorbildlich empfand. Insbesondere auch, was das Zusammenspiel der Objekte/Klassen angeht, das Vorbereiten einer Verbindung und die Nutzung im Bedarfsfalle (lazy connection). Dort werden die Zugangsdaten mit einer statischen Funktion an die abstrakte Db_Adapter-Klasse übergeben, von der die eigene Klasse dann erbt.
Dank und Gruß,
Ahoi,
[1] Abgesehen davon, dass es Muster wie das MVC gibt, die das Ganze zwar noch flexibler dafür aber auch noch komplexer machen.
Könnte man nicht sagen, dass MVC lediglich eine vorhandene Struktur beschreibt. Wenn ich die dann in der Programmierung beachte, bin ich schlussendlich übersichtlicher, nicht komplexer. Statt alles in einen Schrank zu legen, mach ich Schubladen. In dem Fall drei Stück. Oder ich habe drei Abteilungen in einem Betrieb: Lager, Verwaltung, Verkauf. Es soll ja "ordentlicher" und dadurch unkomplizierter werden.
Dank und Gruß,
echo $begrüßung;
» [1] Abgesehen davon, dass es Muster wie das MVC gibt, die das Ganze zwar noch flexibler dafür aber auch noch komplexer machen.
Könnte man nicht sagen, dass MVC lediglich eine vorhandene Struktur beschreibt. Wenn ich die dann in der Programmierung beachte, bin ich schlussendlich übersichtlicher, nicht komplexer.
Natürlich wird das Gesamtsystem komplexer. Vergleich doch mal ein Geradeaus-Script mit einem nach dem MVC-Muster implementierten. Auf den ersten Blick sieht letzteres sicherlich ordentlicher strukturiert und vielleicht einfacher aus, aber du hast nicht mehr nur ein Teil sondern nunmehr drei. Dahinter steckt ja auch noch die Infrastruktur des MVC-Frameworks und da hast du dann deine Komplexität.
Statt alles in einen Schrank zu legen, mach ich Schubladen. In dem Fall drei Stück. [...] Es soll ja "ordentlicher" und dadurch unkomplizierter werden.
Ordentlicher aber komplexer. Die Schubladen brauchen einen Mechanismus zum Rausziehen, der einfache Schrank nur eine Tür. Wenn du etwas suchst, musst du mit Schubladen mehrere Stellen durchsuchen oder du hast zum gezielten Zugriff einen Index auf Papier oder als Erinnerung und bringst wieder ein Stückchen Komplexität hinzu.
echo "$verabschiedung $name";
Ahoi,
Natürlich wird das Gesamtsystem komplexer. Vergleich doch mal ein Geradeaus-Script mit einem nach dem MVC-Muster implementierten.
Ordentlicher aber komplexer. Die Schubladen brauchen einen Mechanismus zum Rausziehen, der einfache Schrank nur eine Tür. Wenn du etwas suchst, musst du mit Schubladen mehrere Stellen durchsuchen oder du hast zum gezielten Zugriff einen Index auf Papier oder als Erinnerung und bringst wieder ein Stückchen Komplexität hinzu.
Es ist doch aber so, dass sehr schnell die Ordnung im Script fehlt, wenn man nicht View, Control und Model trennt. Wenn ich im Schrank die Wäsche nicht gruppiere, dann finde ich nix. Dabei ist es relativ egal, ob ich im Schrank rechts die Unterwäsche, in der Mitte die Hosen und links die Pullis habe oder ob ich dafür extra Schubladen (Klassen) nehme. Ordnung macht es unkomplizierter, wäre die These. Klar, nähme ich ein komplettes Warenwirtschaftssystem nur um mein paar Wäschestücke zu sortieren, wäre das overdone, aber im Kleinen macht man das doch vom Prinzip her dann doch so.
Dank und Gruß,
echo $begrüßung;
Ordnung macht es unkomplizierter, wäre die These.
Ja, natürlich. Das bestreite ich auch gar nicht. Aber Ordnung ist nicht zum Nulltarif zu haben. Du musst ein System einführen, nach dem du ordnest. Anstatt die Wäsche einfach hinter dich zu werfen, musst du erst einmal analysieren, was du gerade in der Hand hast, das Teil kontextgerecht zusammenfalten, auf den passenden Stapel legen und vorher noch einen Zugangsmechanismus (Schublade, Schranktür) zum Stapel betätigen. Ordnung hat seinen Preis in Komplexität.
echo "$verabschiedung $name";
Ich komm immernoch nicht ganz weiter.
Ich habe eine..
database Klasse:
Hier wird nur eine Datenbankverbindung hergestellt als Singleton P..
database.ext. Klasse:
Hier sind sämtliche anderen Datenbankfunktionen drin.
Die Klasse wird in die Main Klasse als Parameter übergeben.
Main Klasse:
Die MainKlasse wird wieder als Singleton P. gemacht
In der index.php wird dann nur dein database Objekt erstellt und ein Main Objekt erstellt.
Aber ich weiß nicht ob das so sinnvoll ist.
Ich komm immer noch nicht weiter wie ich die Klassen untereinander "organisieren" soll.
Verzweifelt..
Chris
Ahoi,
Verzweifelt..
Hast du dir den Link zum Quickstart vom Zend Framework mal angeschaut. Wenn man das durchliest, kann man zumindest nicht verzweifeln.
Dank und Gruß,
echo $begrüßung;
database Klasse:
Hier wird nur eine Datenbankverbindung hergestellt als Singleton P..database.ext. Klasse:
Hier sind sämtliche anderen Datenbankfunktionen drin.
Was sind ihre Aufgaben? Vielleicht können sie ja als Methoden der database-Klasse realisiert werden.
Die Klasse wird in die Main Klasse als Parameter übergeben.
Wenn MainKlasse ein Singleton ist, hieße das, dass mit jedem MainKlasse::getInstance() das ext-Objekt als Parameter übergeben werden muss. Dann kann die MainKlasse sich ein ext-Objekt auch selbst besorgen.
Main Klasse:
Die MainKlasse wird wieder als Singleton P. gemacht
Was ist die Aufgabe der MainKlasse? Ohne zu wissen, was letztlich gelöst werden soll, ist ein konkretes Drübernachdenken nicht sehr sinnig.
In der index.php wird dann nur dein database Objekt erstellt und ein Main Objekt erstellt.
Das database-Objekt wird ja durch das Singleton Pattern in dem Moment erstellt, wenn der erste Zugriff darauf erfolgt. Ein anderweitiges Anlegen ist weder sinnvoll noch nötig und widerspricht auch dem Singleton Pattern, das verlangt, dass der Konstruktor nicht anderweitig aufgerufen werden darf, also private zu sein hat. Die einzige Möglichkeit an ein "gesingletontes" Objekt zu kommen ist der Aufruf der statischen getInstance-Methode (oder wie auch immer man sie nennt). Und jeder, der das Objekt braucht, holt es sich selbst durch Aufruf dieser Methode. Es muss also nicht noch irgendwo anders (global) abgelegt werden.
echo "$verabschiedung $name";
Ahoi,
»» database Klasse:
»» Hier wird nur eine Datenbankverbindung hergestellt als Singleton P..
Bei Zend gibt es für einen Db_Adapter eine factory. Singleton ist der Frontcontroller.
»»
»» database.ext. Klasse:
»» Hier sind sämtliche anderen Datenbankfunktionen drin.
Die bringt wohl der Adapter mit, wie auch die PDOs.
Was sind ihre Aufgaben? Vielleicht können sie ja als Methoden der database-Klasse realisiert werden.
»» Die Klasse wird in die Main Klasse als Parameter übergeben.
Für erweiterte Funktionalität wird bei Zend der Db_Adapter an Db_Table übergeben, eine Klasse, als TableDataGateway fungiert.
Wenn MainKlasse ein Singleton ist, hieße das, dass mit jedem MainKlasse::getInstance() das ext-Objekt als Parameter übergeben werden muss. Dann kann die MainKlasse sich ein ext-Objekt auch selbst besorgen.
Wäre die Main-Klasse der Frontcontroller, würde dieser den Request an einen ActionController routen und der würde dann eine Model-Objekt instantiieren, welches (ggf. via Table-Data-Gateway) auf den Db_Adapter zugreift.
Dank und Gruß,
echo $begrüßung;
Bei Zend gibt es für einen Db_Adapter eine factory. Singleton ist der Frontcontroller.
Da ist ja auch die Aufgabenstellung eine andere. Einen Frontcontroller braucht man nur einen einzigen. Die DB-Factory erzeugt ein konkretes DBMS-spezifisches Objekt aus dem Vorrat der für die unterschiedlichen Systeme vorhandenen Adapter. Damit kann man beliebig viele Verbindungen zu beliebig vielen Servern und Systemen aufbauen. Chris hat aber nicht das Bedürfnis, mehrere Datenbankverbindungen aufzubauen sondern nur eine einzige zu seinem DBMS. Hätte er mehrere Server, die er gleichzeitig kontaktieren will, wäre das Singleton für ihn ungeeignet und eine Fabrik angebracht.
» »» database.ext. Klasse:
» »» Hier sind sämtliche anderen Datenbankfunktionen drin.
Die bringt wohl der Adapter mit, wie auch die PDOs.
Übst du dich im Glaskugellesen? :-)
Für erweiterte Funktionalität wird bei Zend der Db_Adapter an Db_Table übergeben, eine Klasse, als TableDataGateway fungiert.
Ich weiß ja noch nicht, was er im Detail vorhat. Wenn er keinen ORM braucht, ist das ja irrelevant. In meinen bisherigen Ausführen empfahl ich auch keinen ORM. Ein ORM ist ein allgemein gehaltenes Werkzeug. Wenn man aber spezielle Anforderungen hat, zeigt einem der mehr oder wenig starre Mapper schnell mal die seine Grenzen. Es spricht nichts dagegen, einen ORM eines Framworks zu verwenden, wenn der die eigenen Anforderungen erfüllt und man sowieso mit dem Framework arbeitet. Aber jemand, der Erfahrungen mit dem Erstellen einer Daten(bank)zugriffsschicht sammeln will, muss nicht auch gleich noch einen ORM anfangen. Das Zend Framework kann er sich ruhig trotzdem mal ansehen.
» Wenn MainKlasse ein Singleton ist, hieße das, dass mit jedem MainKlasse::getInstance() das ext-Objekt als Parameter übergeben werden muss. Dann kann die MainKlasse sich ein ext-Objekt auch selbst besorgen.
Wäre die Main-Klasse der Frontcontroller, würde dieser den Request an einen ActionController routen und der würde dann eine Model-Objekt instantiieren, welches (ggf. via Table-Data-Gateway) auf den Db_Adapter zugreift.
Nicht jeder Action-Controller hantiert nur mit einem Model. (Zwei oder mehr Action-Controller verkettet oder ein paar Plugins an die Verarbeitungskette angestöpselt und jeder mit Datenbankzugriff wäre auch ein Szenario.) Wenn also mehrere Datenbankzugreifer vorhanden sind, nützt dir die Möglichkeit der Erzeugung über den Db_Adapter noch nicht viel, wenn du am Ende nicht mehrere Verbindungen haben willst oder der Adapter kein Verbindungspooling mitbringt. Du brauchst dann auch noch eine zentrale Ablagestelle (z.B. Repository) und jemanden, der da einen Adapter reinlegt. Oder eben ein Singleton.
echo "$verabschiedung $name";
Ahoi,
Übst du dich im Glaskugellesen? :-)
nein.
»» Für erweiterte Funktionalität wird bei Zend der Db_Adapter an Db_Table übergeben, eine Klasse, als TableDataGateway fungiert.
Ich weiß ja noch nicht, was er im Detail vorhat. Wenn er keinen ORM braucht, ist das ja irrelevant. In meinen bisherigen Ausführen empfahl ich auch keinen ORM. Ein ORM ist ein allgemein gehaltenes Werkzeug. Wenn man aber spezielle Anforderungen hat, zeigt einem der mehr oder wenig starre Mapper schnell mal die seine Grenzen. Es spricht nichts dagegen, einen ORM eines Framworks zu verwenden, wenn der die eigenen Anforderungen erfüllt und man sowieso mit dem Framework arbeitet. Aber jemand, der Erfahrungen mit dem Erstellen einer Daten(bank)zugriffsschicht sammeln will, muss nicht auch gleich noch einen ORM anfangen. Das Zend Framework kann er sich ruhig trotzdem mal ansehen.
Zend macht kein ORM.
»» » Wenn MainKlasse ein Singleton ist, hieße das, dass mit jedem MainKlasse::getInstance() das ext-Objekt als Parameter übergeben werden muss. Dann kann die MainKlasse sich ein ext-Objekt auch selbst besorgen.
»» Wäre die Main-Klasse der Frontcontroller, würde dieser den Request an einen ActionController routen und der würde dann eine Model-Objekt instantiieren, welches (ggf. via Table-Data-Gateway) auf den Db_Adapter zugreift.Nicht jeder Action-Controller hantiert nur mit einem Model. (Zwei oder mehr Action-Controller verkettet oder ein paar Plugins an die Verarbeitungskette angestöpselt und jeder mit Datenbankzugriff wäre auch ein Szenario.) Wenn also mehrere Datenbankzugreifer vorhanden sind, nützt dir die Möglichkeit der Erzeugung über den Db_Adapter noch nicht viel, wenn du am Ende nicht mehrere Verbindungen haben willst oder der Adapter kein Verbindungspooling mitbringt. Du brauchst dann auch noch eine zentrale Ablagestelle (z.B. Repository) und jemanden, der da einen Adapter reinlegt. Oder eben ein Singleton.
Unter "Model" würde ich das Gesamtmodel verstehen. Wenn das aus mehreren Datenbanken sogar bestehen sollte, na denn. Das würde alles in der Model-Klasse verpackt. Der Adapter wird in der Modelklasse dann genutzt oder auch nicht oder mehrere. Zend bietet die Möglichkeit (s.a. Quickstart) eine Zend_Registry zu nutzen. Ein Klasse zur Registrierung von Objekten. Mithin bleibe ich ich dabei, dass man sich dort ganz prima die Schichten anschauen kann. Und im Quickstart ist es jetzt seit kurzem zum ersten Mal mit DB-Zugriff ganz simpel gezeigt (bzw. denk ich mal, simpler geht kaum. Prinzip u.a.: Model != DB).
Dank und Gruß,
echo $begrüßung;
Zend macht kein ORM.
OK, es ist kein ORM sondern ein Table Data Gateway. Beide verfolgen aber ein vergleichbares Ziel.
Unter "Model" würde ich das Gesamtmodel verstehen.
Das ist aber nicht so. Genauso, wie es mehrere Controller und mehrere Views gibt, gibt es mehrere Models. Jeder, jede und jedes hat eine eigene Aufgabenstellung.
Mithin bleibe ich ich dabei, dass man sich dort ganz prima die Schichten anschauen kann.
Vergiss aber bei all deiner Begeisterung für das ZF nicht, dass es nicht das allein selig machende Programmiermodell ist.
echo "$verabschiedung $name";
Ahoi,
echo $begrüßung;
»» Zend macht kein ORM.
OK, es ist kein ORM sondern ein Table Data Gateway. Beide verfolgen aber ein vergleichbares Ziel.
Weißnicht. Da bist du sicher schlauer als ich. Die Methoden beziehen sich halt auf nur eine Tabelle, sind dann aber wieder ähnlich schlußendlich dem PDO.
»» Unter "Model" würde ich das Gesamtmodel verstehen.
Das ist aber nicht so. Genauso, wie es mehrere Controller und mehrere Views gibt, gibt es mehrere Models. Jeder, jede und jedes hat eine eigene Aufgabenstellung.
Da meine ich schon nicht ganz so unsinnige Diskussionen im Web zu gesehen zu haben, vielleicht in Zusammenhang mit Cake-PHP.
»» Mithin bleibe ich ich dabei, dass man sich dort ganz prima die Schichten anschauen kann.
Vergiss aber bei all deiner Begeisterung für das ZF nicht, dass es nicht das allein selig machende Programmiermodell ist.
Ich war halt lange auf der Suche nach _einem_ Beispiel, wie man das sinnig machen kann. Zends Framework baut ja auf auf Pear (oder übernimmt Dinge) und Cake-PHP (wohl auf Pythons Django und Rubys Rails). Und es ist alles sehr stringent und dadurch in der Anlage sehr übersichtlich und dennoch modular und komplett erweiterbar, bzw. wandelbar. Deshalb sehe ich bisher nichts, was beispielhafter wäre. Begeisterung hält sich eigentlich in Grenzen, weil ich oft den Anspruch habe, das müsse doch "selbstverständlich" sein.
Dank und Gruß,
Ahoi,
Da meine ich schon nicht ganz so unsinnige Diskussionen im Web zu gesehen zu haben, vielleicht in Zusammenhang mit Cake-PHP.
http://www.ralfeggert.de/2008/09/21/zend_model-stand-der-dinge/ - http://karwin.blogspot.com/2008/05/activerecord-does-not-suck.html.
Im Quickstart ist es so: der Controller holt sich bei Bedarf eine Instanz des Model_Guestbook. Das wiederum hantiert mit einem Db_Table-Objekt, was es sich über den Db_Adapter besorgt.
Controller spricht zu Model: $this->_model->gibMirDiesUndDas().
Model regelt das dann. Wenn dafür gejoint werden muss, weiß Model was zu tun ist. Nicht Controller. Controller sagt nur $this->_model->gibMirListeVonProduktenMitHerstellerangaben(). So gesehen, hätte das Model zwei Schichten (??), nämlich die der Kommunikation (Interface) mit dem Controller und die der Datenzugriffs.
Die Grundlagen sind ja schon erstaunlich alt (http://www.die.informatik.uni-siegen.de/lehre/EI/informatik1/vorlesung_material/21_MVC.pdf und FUSE http://www.phpfuse.net/ zB. hantiert ja wie Du sagst mit Haufenweisen Model-Klassen http://www.youtube.com/watch?v=cX0eIdWZQhQ.
http://whydoeseverythingsuck.com/2008/02/death-of-relational-database.html kam mir auch schon mal in den Sinn, bzw. die Problematik bei wachsenden Datenstrukturen (http://forum.de.selfhtml.org/archiv/2009/3/t184218/#m1225243.
Ein Link zu der Sache fehlt mir aber noch. Da schrieb jemand (auf Englisch?) das eben Model das komplette Gebilde mit allen Abhängigkeiten und Verbindungen sei, was man darstellen möchte, bzw. der Teil der Realität, den man abbilden möchte. Dazu gehört ja dann im Grunde auch der ganze Schwanz an Metadaten wie Validitäten.
Dank und Gruß,
Hallo.
Danke das ihr mir noch weiterhin helft.
»» database.ext. Klasse:
»» Hier sind sämtliche anderen Datenbankfunktionen drin.Was sind ihre Aufgaben? Vielleicht können sie ja als Methoden der database-Klasse realisiert werden.
In der database.ext sind folgende Methoden enthalten:
######################################################################################################
################# db_make_rwu_sentence
######################################################################################################
// Ein-/Auslesewerte aneinanderreihen
/*
3 Typen:
Typ 1: foo,bar
Typ 2: 'foo','bar'
Typ 3: foo='bar',foo='bar',
Typ 4: ?,?,? - MySQLi Platzhalter für prepared Statements
*/
function db_make_rwu_sentence($what_rwu,$what_insert,$rwu){
$x=0; // Zähler auf NULL(0) setzen
$this->rwu_sentence=''; // Zurücksetzen des Ausdrucks
foreach($what_rwu as $what){
if($rwu==1||$rwu==2){ // Typ 1 oder 2
$this->rwu_sentence .= ($rwu==1) ? $what : "'".$what."'";
} elseif($rwu==3) { // Typ 3
$this->rwu_sentence .= $what."='".$what_insert[$x]."'";
} elseif($rwu==4) { // Typ 4
$this->rwu_sentence .= "?";
}
$this->rwu_sentence .= ($x < $this->count_array - 1) ? "," : "";
++$x; // hochzählen
}
return $this->rwu_sentence;
}
######################################################################################################
################# db_create_normal_query
######################################################################################################
// Erstellt einen Query
function db_create_normal_query($what_array,$what_insert, $from_table, $when, $whatkind){
# Wieviele Werte sind ein-/auszulesen
if($whatkind==1) { // INSERT
$this->db_check_array_numbers($what_array,$what_insert);
$this->count_array=count($what_array);
$this->query="INSERT INTO ".$from_table." (".$this->db_make_rwu_sentence($what_array,'',1);
$this->query.=") VALUES (".$this->db_make_rwu_sentence($what_array,'',4).")";
} elseif ($whatkind==2) { // UPDATE
$this->db_check_array_numbers($what_array,$what_insert);
$this->count_array=count($what_array);
$this->query="UPDATE ".$from_table." SET ";
$this->query.=$this->db_make_rwu_sentence($what_array,$what_insert,3);
$this->query.=" WHERE ".$when;
} elseif ($whatkind==3) { // SELECT
$this->count_array=count($what_array);
$this->query="SELECT ".$this->db_make_rwu_sentence($what_array,'',2)." FROM ".$from_table;
$this->query.=" WHERE ".$when;
} else { // Kein Typ -> Error
$this->db_errors("Es wurde kein Typ ausgewählt");
}
$this->db_prepared_statement($this->query,$whatkind,$what_array);
}
Und darein sollen auch noch:
######################################################################################################
################# db_prepared_statement
######################################################################################################
// Prepared einen Query und führt ihn anschliessend aus
function db_prepared_statement($query,$whatkind,$params){}
######################################################################################################
################# db_errors
######################################################################################################
// Reagiert entsprechend auf Fehler
function db_errors($db_error){
if($this->modus_trialanderror == true){
echo "<h3><pre>".$db_error."</pre></h3>";
} else {
echo "Fehlermodus aus";
}
}
######################################################################################################
################# db_count_found_or_affected_rows
######################################################################################################
// INSERT, UPDATE, REPLACE oder DELETE -> Anzahl der betroffenen Datensätze
// SELECT -> Anzahl der gefundenen Datensätze
function db_count_found_or_affected_rows(){}
######################################################################################################
################# db_fetch_object
######################################################################################################
// Ergebnis auslesen
function db_fetch_object($db_result){
}
######################################################################################################
################# db_close
#####################################################################################################
// Schliesst eine bestehende Datenbank-Verbindung
function db_close(){
}
######################################################################################################
################# db_free_result
#####################################################################################################
// Löscht das Result eines ausgeführten Querys
function db_free_result(){
}
»» Main Klasse:
»» Die MainKlasse wird wieder als Singleton P. gemachtWas ist die Aufgabe der MainKlasse?
Hier sind so "Standard"-Funktionen drin. Ich nenne mal Beispiele:
// Checkt zwei arrays ob sie gleich sind
function check_arrays(}
// Packt alle Requests in ein Array, wahlweise nur alle GET oder nur alle POST Requests
function get_all_requests_in_array(){}
Das database-Objekt wird ja durch das Singleton Pattern in dem Moment erstellt, wenn der erste Zugriff darauf erfolgt. Ein anderweitiges Anlegen ist weder sinnvoll noch nötig und widerspricht auch dem Singleton Pattern, das verlangt, dass der Konstruktor nicht anderweitig aufgerufen werden darf, also private zu sein hat. Die einzige Möglichkeit an ein "gesingletontes" Objekt zu kommen ist der Aufruf der statischen getInstance-Methode (oder wie auch immer man sie nennt). Und jeder, der das Objekt braucht, holt es sich selbst durch Aufruf dieser Methode. Es muss also nicht noch irgendwo anders (global) abgelegt werden.
Achso okay also spart man sich das "$object = new Classname;"
Freue mich über weitere Hilfe ein ordentliches System zu konstruieren. Bilde mich derweil weiter über OOP.
@Frankx
Vielen Dank für die Zend-FW Links. Allerdings möchte auf jeden Fall auf Zend o.ä. verzichten! Ich möchte das System 100% komplett selbstschreiben und mich maximal auf die Module PHP5, MySQLi, mod_rewrite - sprich Standard berufen.
Liebe Grüße,
Chris
echo $begrüßung;
» Was sind ihre Aufgaben? Vielleicht können sie ja als Methoden der database-Klasse realisiert werden.
In der database.ext sind folgende Methoden enthalten:
Mit anderen Worten, sie enthalten Statementerstellung. Das würde Aufgabe einer eigenständigen Klasse sein. Dummerweise braucht man für mysqli::real_escape_string() eine geöffnete Verbindung (und mysqli::set_charset() muss auch ausgeführt sein). Die kannst du dir in deinem Fall über das Singleton holen. Die Statement-Klasse muss man auch mehrfach aufrufen können, um unterschiedliche Statements zu erzeugen. Sie muss also "ganz normal" bleiben.
################# db_make_rwu_sentence
Was heißt rwu? Das solltest du dokumentieren. Außerdem: Schau dir mal die PHPDoc-Syntax an.
if($rwu==1||$rwu==2){ // Typ 1 oder 2 $this->rwu\_sentence .= ($rwu==1) ? $what : "'".$what."'"; } elseif($rwu==3) { // Typ 3 $this->rwu\_sentence .= $what."='".$what\_insert[$x]."'";
Hier fehlt die kontextgerechte Behandlung der Strings. Ein O'Brien macht dir nur einen Syntaxfehler. Ein gezieltes Ausnutzen dieser SQL-Injection-Lücke gefährdet deinen Datenbestand.
$this->query="INSERT INTO ".$from\_table." (".$this->db\_make\_rwu\_sentence($what\_array,'',1);
Auch der Tabellenname erfordert eine kontextgerechte Behandlung, wenn du ihn als einen variablen Bestandteil einfügst. Dafür gibt es aber keine vorgefertigte Funktion, du müsstest dir eine gemäß den Regeln für Identifier selbst erstellen.
$this->query="UPDATE ".$from\_table." SET "; $this->query.=$this->db\_make\_rwu\_sentence($what\_array,$what\_insert,3); $this->query.=" WHERE ".$when;
Schau dir mal die Funktion sprintf() an. Mit der bekommst du die Stringerstellung (meiner Meinung nach) übersichtlicher hin.
$this->query= sprintf("UPDATE %s
SET %s WHERE %s",
escape_table_name($from_table),
$this->db_make_rwu_sentence($what_array,$what_insert,3),
$when);
Und darein sollen auch noch:
function db_prepared_statement($query,$whatkind,$params){}
Zum Erstellen eines mysqli_stmt-Objekts benötigst du ein mysqli-Objekt. Wenn du also noch kein mysqli_stmt-Objekt hast, würde diese Funktion besser in die Basisklasse passen. Als Ergebnis solltest du entweder ein Objekt einer Result-Klasse oder eine andere Datenstuktur bekommen.
Wenn du sowieso die Statements erst noch zusammenbauen lässt, ist das Verwenden von Prepared Statements nicht sehr sinnvoll. Das Handling ist deutlich aufwendiger als das Statement auf herkömmliche Weise (inklusive Maskierung und Quotierung) zu erstellen, mysql::query() aufzurufen und das Ergebnis abzuholen.
################# db_count_found_or_affected_rows
################# db_fetch_object
################# db_free_result
Das ist Bestandteil des Ergebnismengenhandlings. Es ist sinnvoll, das vom Statement zu trennen, denn ein Statement kann mehrere Resultsets liefern (auch wenn du solche Statements wahrscheinlich nicht verwenden wirst).
################# db_close
Keiner deiner DB-Objekt-Verwender kann wissen, wann die Verbindung geschlossen werden kann. Wenn überhaupt, kann nur der Destruktor die Verbindung schließen oder der Automatismus am Scriptende.
» »» Die MainKlasse wird wieder als Singleton P. gemacht
» Was ist die Aufgabe der MainKlasse?
Hier sind so "Standard"-Funktionen drin. Ich nenne mal Beispiele:
function check_arrays(}
function get_all_requests_in_array(){}
Das soll also eigentlich eine Tools/Utility/Helper-Klasse werden. Die Methoden scheinen mir eigenständig arbeiten zu können, sind also nur in den Klassenrahmen gehängte Funktionen. Dann brauchst du keine Instanz und kein Singleton sondern kannst die Methoden als statisch deklarieren.
» Das database-Objekt wird ja durch das Singleton Pattern in dem Moment erstellt, wenn der erste Zugriff darauf erfolgt. Ein anderweitiges Anlegen ist weder sinnvoll noch nötig und widerspricht auch dem Singleton Pattern, das verlangt, dass der Konstruktor nicht anderweitig aufgerufen werden darf, also private zu sein hat. Die einzige Möglichkeit an ein "gesingletontes" Objekt zu kommen ist der Aufruf der statischen getInstance-Methode (oder wie auch immer man sie nennt). Und jeder, der das Objekt braucht, holt es sich selbst durch Aufruf dieser Methode. Es muss also nicht noch irgendwo anders (global) abgelegt werden.
Achso okay also spart man sich das "$object = new Classname;"
Es geht nicht nur um das Sparen sondern um das Unmöglichmachen einer direkten Instantiierung. Sonst kann ja jeder kommen und sich Instanzen erstellen, was das Singleton ad absurdum führte.
Vielen Dank für die Zend-FW Links. Allerdings möchte auf jeden Fall auf Zend o.ä. verzichten!
Ja, aber du kannst ja mal da reinschauen und die Erfahrung die dort drinsteckt in dein Wissen aufzunehmen versuchen.
echo "$verabschiedung $name";
Mit anderen Worten, sie enthalten Statementerstellung. Das würde Aufgabe einer eigenständigen Klasse sein. Dummerweise braucht man für mysqli::real_escape_string() eine geöffnete Verbindung (und mysqli::set_charset() muss auch ausgeführt sein). Die kannst du dir in deinem Fall über das Singleton holen. Die Statement-Klasse muss man auch mehrfach aufrufen können, um unterschiedliche Statements zu erzeugen. Sie muss also "ganz normal" bleiben.
Gut damit steht fest das die DBKlasse Singleton wird. Die Statementklasse werde ich aber auch immer brauchen. Wie also mache ich es damit? das Objekt _immer_ per Parameter übergeben? Schließlich wird es kaum eine Klasse geben ohne Datenbankaktivität. Und hier bin ich schon wieder bei der Ausgangsfrage[[1].
Hier fehlt die kontextgerechte Behandlung der Strings. Ein O'Brien macht dir nur einen Syntaxfehler. Ein gezieltes Ausnutzen dieser SQL-Injection-Lücke gefährdet deinen Datenbestand.
Nein da es eine Klasse geben wird bzw. eine Funktion die alle $_Requests behandelt nach Magic Quotes. Zumindestens habe ich das so vor. hm...
Auch der Tabellenname erfordert eine kontextgerechte Behandlung, wenn du ihn als einen variablen Bestandteil einfügst. Dafür gibt es aber keine vorgefertigte Funktion, du müsstest dir eine gemäß den Regeln für Identifier selbst erstellen.
S.o.
Schau dir mal die Funktion sprintf() an. Mit der bekommst du die Stringerstellung (meiner Meinung nach) übersichtlicher hin.
Jap die kenne ich, habe ich leider garnicht dran gedacht. Danke.
Zum Erstellen eines mysqli_stmt-Objekts benötigst du ein mysqli-Objekt. Wenn du also noch kein mysqli_stmt-Objekt hast, würde diese Funktion besser in die Basisklasse passen. Als Ergebnis solltest du entweder ein Objekt einer Result-Klasse oder eine andere Datenstuktur bekommen.
Wenn du sowieso die Statements erst noch zusammenbauen lässt, ist das Verwenden von Prepared Statements nicht sehr sinnvoll. Das Handling ist deutlich aufwendiger als das Statement auf herkömmliche Weise (inklusive Maskierung und Quotierung) zu erstellen, mysql::query() aufzurufen und das Ergebnis abzuholen.
Hm also wäre es besser die Statements nicht dynamisch zu erzeugen sondern wie sonst auch. Auf prepared Statements möchte ich nicht verzichten.
»» ################# db_count_found_or_affected_rows
»» ################# db_fetch_object
»» ################# db_free_resultDas ist Bestandteil des Ergebnismengenhandlings. Es ist sinnvoll, das vom Statement zu trennen, denn ein Statement kann mehrere Resultsets liefern (auch wenn du solche Statements wahrscheinlich nicht verwenden wirst).
Sprich ich packe das was mit dem RESULT gemacht werden soll in eine extra Klasse? Und diese muss ich auch wieder jeder Klasse mitgeben die mit Datenbank kommuniziert..was mich zu Problem [1] bringt.
»» ################# db_close
Keiner deiner DB-Objekt-Verwender kann wissen, wann die Verbindung geschlossen werden kann. Wenn überhaupt, kann nur der Destruktor die Verbindung schließen oder der Automatismus am Scriptende.
Also entweder weglassen oder die Funktion im Destruktor aufrufen.
»» » »» Die MainKlasse wird wieder als Singleton P. gemacht
»» » Was ist die Aufgabe der MainKlasse?
»» Hier sind so "Standard"-Funktionen drin. Ich nenne mal Beispiele:
»» function check_arrays(}
»» function get_all_requests_in_array(){}Das soll also eigentlich eine Tools/Utility/Helper-Klasse werden. Die Methoden scheinen mir eigenständig arbeiten zu können, sind also nur in den Klassenrahmen gehängte Funktionen. Dann brauchst du keine Instanz und kein Singleton sondern kannst die Methoden als statisch deklarieren.
Ach wenn ich sie als statisch deklariere kann ich immer auf sie zugreifen? Da hab ich wohl irgendwas beim lernen übersehen. Also sind sie dadurch auch global oder wie läuft das ab weil sie werden ja nicht eingebunden(extends / Parameter).
»» » Das database-Objekt wird ja durch das Singleton Pattern in dem Moment erstellt, wenn der erste Zugriff darauf erfolgt. Ein anderweitiges Anlegen ist weder sinnvoll noch nötig und widerspricht auch dem Singleton Pattern, das verlangt, dass der Konstruktor nicht anderweitig aufgerufen werden darf, also private zu sein hat. Die einzige Möglichkeit an ein "gesingletontes" Objekt zu kommen ist der Aufruf der statischen getInstance-Methode (oder wie auch immer man sie nennt). Und jeder, der das Objekt braucht, holt es sich selbst durch Aufruf dieser Methode. Es muss also nicht noch irgendwo anders (global) abgelegt werden.
Gut - verstanden.
»» Achso okay also spart man sich das "$object = new Classname;"
Es geht nicht nur um das Sparen sondern um das Unmöglichmachen einer direkten Instantiierung. Sonst kann ja jeder kommen und sich Instanzen erstellen, was das Singleton ad absurdum führte.
Achso.
Ja, aber du kannst ja mal da reinschauen und die Erfahrung die dort drinsteckt in dein Wissen aufzunehmen versuchen.
Du hast Recht das werde ich tun.
Hoffe du hilfst mir weiterhin.
Vielen Dank.
Gruß,
Chris
echo $begrüßung;
Gut damit steht fest das die DBKlasse Singleton wird. Die Statementklasse werde ich aber auch immer brauchen. Wie also mache ich es damit? das Objekt _immer_ per Parameter übergeben? Schließlich wird es kaum eine Klasse geben ohne Datenbankaktivität. Und hier bin ich schon wieder bei der Ausgangsfrage[[1].
Jeder der mit Hilfe dieser Statementklasse ein solches zusammenbauen will, instantiiert sich ein Objekt selbst. Außerdem braucht es eine Referenz auf die DBKlasse, die du über das Singleton bekommst, der du das Statement zum Abarbeiten übergibst.
» Zum Erstellen eines mysqli_stmt-Objekts benötigst du ein mysqli-Objekt. Wenn du also noch kein mysqli_stmt-Objekt hast, würde diese Funktion besser in die Basisklasse passen. Als Ergebnis solltest du entweder ein Objekt einer Result-Klasse oder eine andere Datenstuktur bekommen.
Sprich ich packe das was mit dem RESULT gemacht werden soll in eine extra Klasse? Und diese muss ich auch wieder jeder Klasse mitgeben die mit Datenbank kommuniziert..was mich zu Problem [1] bringt.
Von der Abarbeitungsmethode bekommst du ein Ergebnis. Das kann ein Array sein oder auch eine Ergebnisklasse, von der man das Ergebnis schrittweise abholen kann und der man auch noch mehr Funktionalität hinzuprogrammieren kann, wenn man das braucht.
Wenn Methode X ein Ergebnis produziert, erzeugt sie auch intern eine passende Struktur, befüllt sie mit dem Ergebnis und gibt die Struktur zurück. Die Struktur kann eine Variable, ein Array oder auch ein Objekt sein. Es ist normalerweise nicht nötig, die Ergebnisstruktur vor dem Aufruf von X zu erzeugen. (Das kann zwar auch ein Anwendungsfall sein, den sehe ich aber so pauschal hier nicht.)
Ich schrieb gestern, die Statementerzeugung solle in die Basisklasse. Oben schrieb ich, jeder instantiiere sie sich selbst. Es kommt darauf an, was du letztlich implementierst. Willst du ein Prepared Statement erstellen inklusive der Instanz eines mysqli_stmt-Objekts, dann lass es dir mit einer Methode der DBKlasse erzeugen, denn um ein mysqli_stmt zu bekommen musst du die mysqli-Klasseninstanz bemühen. Willst du ein SQL-Statement unabhängig von mysqli_stmt erstellen, also nur den Statement-String zusammensetzen, dann sollte eine Instanz vor Ort erzeugt werden.
Wir haben also nun zwei mögliche Wege
a) mysqli_stmt
b) SQL-Statement-String
Für a) gibt es DBKlasse::getStatememt(), damit bekommst du eine mysqli_stmt-Instanz. Der übergibst du den SQL-String sowie die Parameter, lässt das Ganze exekutieren und hast ein Ergebnis
Für b) erstellst du mit der SQL-String-Klasse den SQL-String und rufst
$db = DBKlasse::getInstance()
$result = $db->führeAus($sql_instanz)
auf.
» Hier fehlt die kontextgerechte Behandlung der Strings. Ein O'Brien macht dir nur einen Syntaxfehler. Ein gezieltes Ausnutzen dieser SQL-Injection-Lücke gefährdet deinen Datenbestand.
Nein da es eine Klasse geben wird bzw. eine Funktion die alle $_Requests behandelt nach Magic Quotes. Zumindestens habe ich das so vor. hm...
Zum einen ist vom Verwenden des ungezielten $_REQUEST unbedingt abzuraten, holt man sich doch damit ohne weitere Gegenmaßnamen beispielsweise CSRF-Probleme ins Haus. Frag gezielt nach $_POST und $_GET, wenn du die Daten auf dem jeweilen Weg erwartest. Zum anderen ist es überhaupt nicht sinnvoll, gleich am Engang die Daten für nur einen möglichen Ausgang zu bearbeiten. Damit sind sie nämlich für alle anderen Ausgänge unbrauchbar. Du nagelst dich damit also auf genau einen Verarbeitungsweg fest. Besser ist es, die Daten am jeweiligen Eingang eventuell von ihrer Transportsicherung zu befreien, sie also ins Rohformat zu bringen und erst am jeweiligen Ausgang gemäß dessen Regeln zu behandeln. Damit lässt du dir alle möglichen Kombinationen von Eingang zu Ausgang offen. Für die Platzhalter eines Prepared Statments brauchst du die Daten in Rohform, Selbst eingefügt in einen SQL-String musst du sie behandeln. Du siehst also, dass für eines der beiden Ziele eine oder keine vorbeugende Behandlung am Eingang sie nicht in das jeweils erforderliche Format bringt.
» Auch der Tabellenname erfordert eine kontextgerechte Behandlung, wenn du ihn als einen variablen Bestandteil einfügst. Dafür gibt es aber keine vorgefertigte Funktion, du müsstest dir eine gemäß den Regeln für Identifier selbst erstellen.
S.o.
Na, der Tabellenname kommt doch wohl nicht aus einer Benutzereingabe oder programmierst du phpMyAdmin nach?
Hm also wäre es besser die Statements nicht dynamisch zu erzeugen sondern wie sonst auch. Auf prepared Statements möchte ich nicht verzichten.
Wie gesagt und in meiner ersten Antwort verlinkt, ist das Verwenden von Prepared Statements unter mysqli mit einer variablen Anzahl an Parametern mit einem aufwendigeren Handling verbunden als der herkömmliche Weg. Du bist mit herkömmlichen Weg genauso sicher wie mit P.S., wenn du an die kontextgerechte Behandlung denkst. P.S. bringen dir hier nur dann einen Vorteil (im Verhältnis zum Aufwand gesehen), wenn du ein P.S. mehrfach hintereinander ausführen kannst (z.B. Massen-Insert).
» Das soll also eigentlich eine Tools/Utility/Helper-Klasse werden. Die Methoden scheinen mir eigenständig arbeiten zu können, sind also nur in den Klassenrahmen gehängte Funktionen. Dann brauchst du keine Instanz und kein Singleton sondern kannst die Methoden als statisch deklarieren.
Ach wenn ich sie als statisch deklariere kann ich immer auf sie zugreifen? Da hab ich wohl irgendwas beim lernen übersehen. Also sind sie dadurch auch global oder wie läuft das ab weil sie werden ja nicht eingebunden(extends / Parameter).
Statische Methoden sind immer an die Klasse gebunden [1], in der sie deklariert sind. Der Aufruf erfolgt über
[$ergebnis =] Klassenname::Methodenname([$parameter]);
Sie sind damit wie eine normale Funktion global [2], nur dass sie eben den Klassennamen zum Aufruf braucht.
[1] abgesehen von PHP 5.3 und dem Late Static Binding
[2] public als Sichtbarkeitsmodifizierer vorausgesetzt.
echo "$verabschiedung $name";
Hallo.
Gut, ich werde auf dynamisch erzeugte Statements verzichten.
Die DB-Klasse wird Singleton.
Die Tools/Help/Utility Klasse wird statisch aufgebaut, also die Funktionen werden static.
So kann ich ohne Sie zu instanzieren per Klassenname::Funktionsname() auf sie zugreifen.
Desweiteren werde ich die Requests immer örtlich behandeln, bei MySQLi mit P.S. ist dies nicht nötig da MySQLi dies übernimmt. Sie bekommen die unbehandelen Rohdaten.
Ich überlege gerade folgendes. Da MySQLi ja eh komplett OOP ist, brauche ich ja rein theoretisch garkeine DB Klasse. Ich wil trotzdem eine machen um ggf. irgendwann falls nötig auf ein anderes DBMS umsteigen zu können, eine DBKlasse machen.
Aber wenn man das jetzt mal alles zusammenfasst, sollte diese nur die Methoden "db_connect" sowie "db_prepare", "db_bind"(für bind_param / bind_result), "db_execute" beinhalten, welche ja voneinander abhängig sind irgendwo. Also packe ich die letzten Methoden jetzt in eine extra Klasse und sie bekommen das benötigte MySQLi-Objekt als Singleton oder kommen sie auch in die DB_Klasse und immer wenn ein MySQLi-Objekt per getInstance() erzeugt wird, wird dieses Objekt einer Variable der DBKlasse übergeben auf das die anderen Methoden der Klasse dann immer zurückgreifen können?
Tut mir leid wenn ich dir gerade das Gefühl gebe gegen ne Wand zu labern.
Ich schrieb gestern, die Statementerzeugung solle in die Basisklasse. Oben schrieb ich, jeder instantiiere sie sich selbst. Es kommt darauf an, was du letztlich implementierst. Willst du ein Prepared Statement erstellen inklusive der Instanz eines mysqli_stmt-Objekts,
Das check ich nicht.
dann lass es dir mit einer Methode der DBKlasse erzeugen, denn um ein mysqli_stmt zu bekommen musst du die mysqli-Klasseninstanz bemühen. Willst du ein SQL-Statement unabhängig von mysqli_stmt erstellen, also nur den Statement-String zusammensetzen, dann sollte eine Instanz vor Ort erzeugt werden.
Wir haben also nun zwei mögliche Wege
a) mysqli_stmt
b) SQL-Statement-StringFür a) gibt es DBKlasse::getStatememt(), damit bekommst du eine mysqli_stmt-Instanz. Der übergibst du den SQL-String sowie die Parameter, lässt das Ganze exekutieren und hast ein Ergebnis
Für b) erstellst du mit der SQL-String-Klasse den SQL-String und rufst
$db = DBKlasse::getInstance()
$result = $db->führeAus($sql_instanz)
auf.
Das verwirrt mich gerade.
Ich will das performante&sichere.
Also ich ging jetzt irgendwie davon aus einfach nur MySQLi zu benutzen als Singeton Pattern und wenn ich nun ein MySQLi Objekt erzeuge dann kann ich damit die Methoden prepare(), execute(), bind_param(), bind_result() usw nutzen. Ich verstehe nicht den Unterschied zwischen MySQLi_stmt und normalem MySQli oder isses beide das gleiche? Kann es ja nicht wie man hier und hier sieht. Aber irgendwie können sie doch nur beides das gleiche oder? Wann verwende ich denn was davon?
Mein Ziel war es einfach die Möglichkeit von Multi-Querys zu nutzen und die Tatsache das dass benutzen von Prepared Statements schneller und sicher ist, sowie das ganze OOP ist.
»» » Hier fehlt die kontextgerechte Behandlung der Strings. Ein O'Brien macht dir nur einen Syntaxfehler. Ein gezieltes Ausnutzen dieser SQL-Injection-Lücke gefährdet deinen Datenbestand.
»» Nein da es eine Klasse geben wird bzw. eine Funktion die alle $_Requests behandelt nach Magic Quotes. Zumindestens habe ich das so vor. hm...
Das lasse ich dann wie oben schon erwähnt sein.
Na, der Tabellenname kommt doch wohl nicht aus einer Benutzereingabe oder programmierst du phpMyAdmin nach?
Nein aber es wird eine Settings.php geben und dort stehen MySQL Daten, Tabellennamen mit Kommentierung usw. drin. D.h. wenn ich später iwas ändern muss, dann tu ich das erstmal in der Settings PHP. Wenn das etwas anders behandelt werden soll, an den Klassen.
Wie gesagt und in meiner ersten Antwort verlinkt, ist das Verwenden von Prepared Statements unter mysqli mit einer variablen Anzahl an Parametern mit einem aufwendigeren Handling verbunden als der herkömmliche Weg. Du bist mit herkömmlichen Weg genauso sicher wie mit P.S., wenn du an die kontextgerechte Behandlung denkst. P.S. bringen dir hier nur dann einen Vorteil (im Verhältnis zum Aufwand gesehen), wenn du ein P.S. mehrfach hintereinander ausführen kannst (z.B. Massen-Insert).
Dann bleibe ich bei P.S. denn das ist das was ich von Anfang an wollte. Einfach um meinen Horizont zu erweitern und aus den Gründen der in meiner Ansicht Vereinfachung.
Sie sind damit wie eine normale Funktion global [2], nur dass sie eben den Klassennamen zum Aufruf braucht.
Wo liegt denn dann der Unterschied zwischen Singleton P. und eine public static Methode? Letzteres ist sicherer aufgrund des Public Sichtbarkeitsmodofizierer?
Liebe Grüße,
Chris
echo $begrüßung;
Ich überlege gerade folgendes. Da MySQLi ja eh komplett OOP ist, brauche ich ja rein theoretisch garkeine DB Klasse. Ich wil trotzdem eine machen um ggf. irgendwann falls nötig auf ein anderes DBMS umsteigen zu können, eine DBKlasse machen.
Bedenke, dass der Umstieg normalerweise deshalb erfolgt, weil man Feature X haben will, dass im alten System nicht vorhanden war. Es erfordert dann meist auch ein grundlegendes Umstricken des DB-Handlings und mancher Statements (andere Syntax).
Aber wenn man das jetzt mal alles zusammenfasst, sollte diese nur die Methoden "db_connect" sowie "db_prepare", "db_bind"(für bind_param / bind_result), "db_execute" beinhalten, welche ja voneinander abhängig sind irgendwo. Also packe ich die letzten Methoden jetzt in eine extra Klasse und sie bekommen das benötigte MySQLi-Objekt als Singleton oder kommen sie auch in die DB_Klasse und immer wenn ein MySQLi-Objekt per getInstance() erzeugt wird, wird dieses Objekt einer Variable der DBKlasse übergeben auf das die anderen Methoden der Klasse dann immer zurückgreifen können?
Du scheinst das Singleton Pattern noch nicht verstanden zu haben. Es muss nichts rumgereicht werden. Jeder kann sich die Instanz beim S. abholen, wenn er sie braucht.
Meine Vorgehensweise wäre, eine DB-Klasse zu erstellen, die irgendwie die Zugangsdaten bekommt und eine Methode bereitstellt, mit der man SQL-Statements ausführen und eine Ergebnismenge zurückbekommen kann. Das heißt, am Ende hat sie eine öffentliche Methode (plus gegebenenfalls Zugangsdatenübergabe). Man übergibt das vollständige SQL-Statement oder eins mit Platzhaltern zuzüglich der Werte. Alles weitere passiert intern. Die Methode kann sogar statisch sein, wenn keine weiteren öffentlichen Hilfsmethoden benötigt werden.
» Ich schrieb gestern, die Statementerzeugung solle in die Basisklasse. Oben schrieb ich, jeder instantiiere sie sich selbst. Es kommt darauf an, was du letztlich implementierst. Willst du ein Prepared Statement erstellen inklusive der Instanz eines mysqli_stmt-Objekts,
Das check ich nicht.
Es ist vielleicht etwas verwirrend, weil der Begriff Statement oftmals und mit unterschiedlicher Bedeutung auftaucht. Wenn "SQL" dabeisteht, dann ist ein SQL-Statement-String gemeint ("SELECT ...", "INSERT ...") ansonsten ein Prepared Statement, also ein Objekt, dass einen SQL-Statement-String bekommen kann und mit Werten verbunden und exekutiert werden kann.
Ich will das performante&sichere.
Performanter dürfte sein, auf (mysqli-) P.S. zu verzichten, wenn SQL-Statements erst noch zusammengebaut werden müssen und wenn Ergebnisse mit unterschiedlichen Spaltenanzahlen abgeholt werden müssen. Die Sicherheit lässt sich mit Maskieren erreichen.
Ich verstehe nicht den Unterschied zwischen MySQLi_stmt und normalem MySQli oder isses beide das gleiche?
Es gibt drei Klassen innerhalb der mysqli-Extension: mysqli, mysqli_stmt und mysqli_result. (Die vierte (mysqli_driver) ist uninteressant.) Eine mysqli-Klasse brauchst du immer. mysqli_result bekommst du als Ergebnis eines mysqli::query(). und mysqli::prepare() liefert dir ein mysqli_stmt-Objekt, an das du deine Parameter- und Result-Variablen binden musst sowie execute() und fetch() aufrufst. Wenn dir das soweit noch nicht klar ist, übe doch erst einmal den Umgang mit der mysqli-Extension, bevor du eine DB-API drumherum entwickelst.
Mein Ziel war es einfach die Möglichkeit von Multi-Querys zu nutzen und die Tatsache das dass benutzen von Prepared Statements schneller und sicher ist, sowie das ganze OOP ist.
Multi-Querys sind noch mal eine Kategorie für sich. Da kommen dann noch weitere Herausforderungen auf dich zu, wie der Umgang mit mehreren Resultsets. Schneller können P.S. nur sein, wenn man sie so verwendet, wie vorgesehen.
Wo liegt denn dann der Unterschied zwischen Singleton P. und eine public static Methode? Letzteres ist sicherer aufgrund des Public Sichtbarkeitsmodofizierer?
Eine statische Methode ist eine Methode einer Klasse, die ohne Instanz aufgerufen werden kann. Das Singleton Pattern ist mehr, es nutzt aber eine statische Methode, um seine Aufgabe zu erfüllen. Zunächst muss der Konstruktor private sein, damit keine Instanz direkt erzeugt werden kann. Neben der statischen öffentlichen Methode gibt es noch eine statische und private Eigenschaft, in der die Instanz geparkt wird, wenn sie bei der ersten Anforderung erzeugt wird. Anforderungen kommen immer über die statische Methode. Die gibt die geparkte Instant raus und instantiiert beim Erstaufruf vorher diese Instanz und legt sie in der statischen Eigenschaft ab. Wie das als Code aussieht ist im PHP-Handbuch zu sehen: Singleton Pattern.
echo "$verabschiedung $name";
Hi.
Meine Vorgehensweise wäre, eine DB-Klasse zu erstellen, die irgendwie die Zugangsdaten bekommt und eine Methode bereitstellt, mit der man SQL-Statements ausführen und eine Ergebnismenge zurückbekommen kann. Das heißt, am Ende hat sie eine öffentliche Methode (plus gegebenenfalls Zugangsdatenübergabe). Man übergibt das vollständige SQL-Statement oder eins mit Platzhaltern zuzüglich der Werte. Alles weitere passiert intern. Die Methode kann sogar statisch sein, wenn keine weiteren öffentlichen Hilfsmethoden benötigt werden.
Also etwa so?:
class db{
var $host;
var $name;
var $pw;
var $dbname;
private static $instance = NULL;
privat function __construct(){}
public function getValues($host,$name,$pw,$dbname){
$this->$host=$host;
// usw..
}
// Zur DB connecten
function dbconnect(){}
// Singleton
public static function getInstance() {}
// Klonen verbieten.
private function __clone() {}
public function prepare_bind_execute_stmt($sql,$thevalues){}
}
Ich denke so meintest du das nicht oder?
»» Ich will das performante&sichere.
Performanter dürfte sein, auf (mysqli-) P.S. zu verzichten, wenn SQL-Statements erst noch zusammengebaut werden müssen und wenn Ergebnisse mit unterschiedlichen Spaltenanzahlen abgeholt werden müssen. Die Sicherheit lässt sich mit Maskieren erreichen.
Jetzt zweifel ich ob ich überhaupt umsteigen soll von MySQL auf Improved.
»» Ich verstehe nicht den Unterschied zwischen MySQLi_stmt und normalem MySQli oder isses beide das gleiche?
Es gibt drei Klassen innerhalb der mysqli-Extension: mysqli, mysqli_stmt und mysqli_result. (Die vierte (mysqli_driver) ist uninteressant.) Eine mysqli-Klasse brauchst du immer. mysqli_result bekommst du als Ergebnis eines mysqli::query(). und mysqli::prepare() liefert dir ein mysqli_stmt-Objekt, an das du deine Parameter- und Result-Variablen binden musst sowie execute() und fetch() aufrufst. Wenn dir das soweit noch nicht klar ist, übe doch erst einmal den Umgang mit der mysqli-Extension, bevor du eine DB-API drumherum entwickelst.
Danke, da blick ich durch =).
Multi-Querys sind noch mal eine Kategorie für sich. Da kommen dann noch weitere Herausforderungen auf dich zu, wie der Umgang mit mehreren Resultsets.
Ich will halt z.b. einen Eintrag "User, Password" machen und direkt im Anschluss die durch die auto_increment erzeugte Spalte "id" auslesen.
Also bei mir wären das eigendlich zwei Querys. Dank Mulitqueries nicht mehr.
Schneller können P.S. nur sein, wenn man sie so verwendet, wie vorgesehen.
Das wäre ganz klipp und klar wenn ich sie wie verwende?
»» Wo liegt denn dann der Unterschied zwischen Singleton P. und eine public static Methode? Letzteres ist sicherer aufgrund des Public Sichtbarkeitsmodofizierer?
Eine statische Methode ist eine Methode einer Klasse, die ohne Instanz aufgerufen werden kann. Das Singleton Pattern ist mehr, es nutzt aber eine statische Methode, um seine Aufgabe zu erfüllen. Zunächst muss der Konstruktor private sein, damit keine Instanz direkt erzeugt werden kann. Neben der statischen öffentlichen Methode gibt es noch eine statische und private Eigenschaft, in der die Instanz geparkt wird, wenn sie bei der ersten Anforderung erzeugt wird. Anforderungen kommen immer über die statische Methode. Die gibt die geparkte Instant raus und instantiiert beim Erstaufruf vorher diese Instanz und legt sie in der statischen Eigenschaft ab. Wie das als Code aussieht ist im PHP-Handbuch zu sehen: Singleton Pattern.
Danke, auch verstanden =).
Ich komme hiermit nochmal auf
Meine Vorgehensweise wäre[...]
zurück. Wie sähe die im Gesamtbild aus?
Es gibt immer noch 3 Klassen bei mir.
Tools, DBMS_Connection, DBMS_functions
so in etwa.
Tools werden die Methoden static?
DBMS_Connection wird Singleton und DBMS_functions wieder alles static?
Ich brauche alles 3 fast immer, sprich sie alle drei müssen für alle Methoden und Klassen verfügbarstehen. Mit Singleton, das ist mir nun klar.
Wie ich das mit den beiden anderen handhabe noch nicht ganz.
Liebe Grüße,
Chris
echo $begrüßung;
Ich denke so meintest du das nicht oder?
Nicht ganz, aber so in etwa. Du holst dir zunächst über getInstanz ein DB-Objekt und rufst dann davon die prepare_bind_execute_stmt()-Methode auf. Das ist auch o.k.
Die Übergabe der Verbindungsparameter sollte aber anders gelöst werden. Die müssen ja schon vor dem Erstaufruf von getInstance() bekannt sein, denn diese Methode benötigt die Daten ja schon, denn die Notwendigkeit eines Connects kann unmittelbar darauf gegeben sein. Statische Klassenvariablen und eventuell eine statische Methode, mit der alle vier gleichzeitig gesetzt werden können, sehe ich dafür als eine geeignete Möglichkeit an.
Jetzt zweifel ich ob ich überhaupt umsteigen soll von MySQL auf Improved.
Du kannst ruhig Improved verwenden, dann aber auf herkömmlichem Weg à la: connect, query und $result->fetch.
Ich will halt z.b. einen Eintrag "User, Password" machen und direkt im Anschluss die durch die auto_increment erzeugte Spalte "id" auslesen.
Also bei mir wären das eigendlich zwei Querys. Dank Mulitqueries nicht mehr.
Für diesen Trivialfall brauchst du keine zwei Querys. Der auto_increment-Wert des letzten Insert-Statements steht in der Eigenschaft insert_id des mysqli-Objekts (oder im Prepared-Statements-Fall in der gleichnamigen Eigenschaft des mysqli_stmt-Objekts).
» Schneller können P.S. nur sein, wenn man sie so verwendet, wie vorgesehen.
Das wäre ganz klipp und klar wenn ich sie wie verwende?
So wie es das Beispiel zu mysqli_stmt::bind_result() vorsieht. Du hast genau zwei Variablen zu binden, weil das SELECT-Statement zwei Werte zurückgibt. Und mit denen machst du direkt etwas in jeder while-fetch-Runde. Wenn du eine unvorhersehbare Anzahl Werte hast, ist das Binden umständlicher. Und wenn du die Werte nicht sofort verarbeiten willst sondern erst noch zwischenspeichern, wird es noch etwas umständlicher. Dazu hab ich ja schon mal ein Beispiel verlinkt.
Ich komme hiermit nochmal auf
» Meine Vorgehensweise wäre[...]
zurück. Wie sähe die im Gesamtbild aus?
Erstell doch mal eine Implementation an und probier die aus. Du wirst dann schon sehen, was du dazu noch brauchst. Sie wird sicher nicht gleich beim ersten Wurf perfekt sein, egal wie lange du vorher planst und die Möglichkeiten beleuchtest.
echo "$verabschiedung $name";
Hi.
Nicht ganz, aber so in etwa. Du holst dir zunächst über getInstanz ein DB-Objekt und rufst dann davon die prepare_bind_execute_stmt()-Methode auf. Das ist auch o.k.
Die Übergabe der Verbindungsparameter sollte aber anders gelöst werden. Die müssen ja schon vor dem Erstaufruf von getInstance() bekannt sein, denn diese Methode benötigt die Daten ja schon, denn die Notwendigkeit eines Connects kann unmittelbar darauf gegeben sein. Statische Klassenvariablen und eventuell eine statische Methode, mit der alle vier gleichzeitig gesetzt werden können, sehe ich dafür als eine geeignete Möglichkeit an.
Okay wird geändert.
Du kannst ruhig Improved verwenden, dann aber auf herkömmlichem Weg à la: connect, query und $result->fetch.
Hm okay, wenn dann mal was kommt wo sich P.S. lohnt, kann man es ja noch nutzen.
Für diesen Trivialfall brauchst du keine zwei Querys. Der auto_increment-Wert des letzten Insert-Statements steht in der Eigenschaft insert_id des mysqli-Objekts (oder im Prepared-Statements-Fall in der gleichnamigen Eigenschaft des mysqli_stmt-Objekts).
Gut zu wissen =) ich sollte mir die MySQLi Klasse nochmal ganz genau anschauen. Aber wenn ich zum Beispiel eine Aufwendige Registrierung habe oder das löschen eines Useres und seine Forumbeiträge... Also etwas wo ich auf mehrere Tabellen zugreifen muss und was mit JOINS einfach sehr sehr komplex werden würde...
Erstell doch mal eine Implementation an und probier die aus. Du wirst dann schon sehen, was du dazu noch brauchst. Sie wird sicher nicht gleich beim ersten Wurf perfekt sein, egal wie lange du vorher planst und die Möglichkeiten beleuchtest.
Das werde ich tun, ich hoffe du lässt den Thread hier noch bei dir angezeigt so das du mir ggf. in 1-2 Tagen nochmal helfen kannst, denn heute - komm ich da nicht mehr zu.
Vielen Dank.
Chris
echo $begrüßung;
» [Multi-Query]
Aber wenn ich zum Beispiel eine Aufwendige Registrierung habe oder das löschen eines Useres und seine Forumbeiträge... Also etwas wo ich auf mehrere Tabellen zugreifen muss und was mit JOINS einfach sehr sehr komplex werden würde...
Das kann ein Fall für eine Multi-Query sein. Besser wäre es, den in einer Stored Procedure zu kapseln.
Das Ausführen mehrerer Statements in einem Aufruf wurde ja nicht umsonst aus dem Standard-Programm genommen. Der Grund dahinter war, das Verwenden von SQL-Injections des Kalibers Exploits of a Mom zu verhindern. Mit dem "normalen" mysql(i)_query() ergibt solch ein Versuch nur einen Syntax-Fehler. Wenn jemand eine SQL-Injection-Lücke in einem Statement hat und dies mit mysql(i)_query() ausführt, kann man dieses "nur" erweitern. Aber da steckt auch noch genug Missbrauchspotential drin.
Lass also bei Multi-Query noch mehr Vorsicht walten als bei einfachen Querys.
echo "$verabschiedung $name";
Danke dedlfix und Sven R. für die ausführlichen Antworten.
lg, chris