dedlfix: Komplettes Projekt in OOP

Beitrag lesen

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";