Dedlfix hilf mir nochmal eben - OOP Datenbankklasse
Chris
- php
Moinsen Dedl.
http://forum.de.selfhtml.org/archiv/2009/4/t185544/#m1232571
Schau mal da hattest du mir eine Query-Methode für eine Datenbankklasse geschrieben.
Könntest du mir folgende Dinge erklären:
1. Wann machst du um Schleifen und If-Abfragen {} und wann nicht?
2. Wie kann ich die Klasse so umbauen das folgendes passiert:
Ich habe ja die Wahl mir das Ergebnis als Array oder Objekt zurückgeben zu lassen. Aber was ist mit INSERT, UPDATE, DELETE?
Von sollchen Queries möchte ich auch einen Rückgabewert - true oder false.
Je nachdem ob der Query erfolgreich war oder nicht.
Und wie implementiere ich am besten die Anzahl der betroffenen Datensätze?
Mit affected Rows oder mit count($result).
Ich blick aufgrund deiner meist nicht vorhandenen Klammern , nicht durch, wo ich ansetzen muss um diese Methode zu erweitern.
Danke schonmal.
Bye, bye, Chris
Ich blick aufgrund deiner _manchmal_ nicht vorhandenen Klammern , nicht durch, wo ich ansetzen muss um diese Methode zu erweitern.
echo $begrüßung;
http://forum.de.selfhtml.org/archiv/2009/4/t185544/#m1232571
- Wann machst du um Schleifen und If-Abfragen {} und wann nicht?
if und auch while, for und foreach erlauben eine einzelne Anweisung zu notieren. Will man mehrere Anweisungen ausführen, muss man sie {}-klammern. Es ist auch erlaubt, bei nur einer Anweisung die Klammern zu setzen. Manche machen das immer, ich nicht. Ich sehe auch anhand der Einrückung, was zum if gehört und was nicht mehr. (Ein Hoch auf Python! Struktur wird dort durch Einrückung verwaltet und nicht mit einem Klammernwald.)
Normalerweise bekommt man dieses Wissen beim erstmaligen Kontakt mit Literatur vermittelt, die unter anderem auch in diese Kontrollstrukturen einführt.
Ich habe ja die Wahl mir das Ergebnis als Array oder Objekt zurückgeben zu lassen. Aber was ist mit INSERT, UPDATE, DELETE?
Von sollchen Queries möchte ich auch einen Rückgabewert - true oder false.
Je nachdem ob der Query erfolgreich war oder nicht.
Im Falle eines Fehlers wird die Verarbeitung mit einer Exception abgebrochen.
$mysqliResult = $mysqli->query($sql, MYSQLI_USE_RESULT);
if (!$mysqliResult)
throw new Exception(...);
"Nicht erfolgreich" ist normalerweise solch ein Fehler, der durch falsche Syntax, fehlende Berechtigungen oder Störungen bei der Kommunikation mit dem DBMS hervorgerufen wird. Wenn du jedoch unter "nicht erfolgreich" verstehst, dass keine Datensätze geändert wurden, ansonsten aber alles bestens war, dann ergibt sich diese Information aus der Anzahl der betroffenen Datensätze, denn die ist dann 0. Allerdings ist sie auch dann 0, wenn ein Änderungswunsch keine echte Änderung vornehmen würde. UPDATE ... SET feld='foo' wenn bereits 'foo' im Feld steht. Das Verhalten kann man mit dem Flag MYSQLI_CLIENT_FOUND_ROWS steuern, wenn man zum Verbindungsaufbau mysqli::real_connect() verwendet.
Bei Statements mit Ergebnismenge gibt es ein mysqli_result, bei den anderen nicht.
if ($mysqliResult instanceof mysqli_result) {
...
}
Von den drei möglichen Zuständen "erfolgreich", "nicht erfolgreich" und "Ergebnismenge" bleibt nur noch "erfolgreich" übrig. Im (bisher nicht vorhandenen) else-Zweig kannst du dafür eine Verarbeitung unterbringen.
Und wie implementiere ich am besten die Anzahl der betroffenen Datensätze?
Neben der Anzahl der betroffenen Datensätze bei Update und Delete ist bei Inserts oft auch noch die eingefügte Auto-Increment-ID interessant.
Mit affected Rows oder mit count($result).
Eine Ergebnismenge entsteht nur bei R, nicht aber bei UDI [*]. Bei UDI fällt nur die Anzahl der betroffenen Datensätze (affected Rows) an und diese muss aus der Eigenschaft mysqli->affected_rows gelesen werden.
Da die Ergebnismenge als Array mit je einem Eintrag pro Datensatz zurückgegeben wird, kann die Anzahl der Datensätze vom Empfänger mit einem count() ermittelt werden.
Bleibt übrig, die Anzahl der affected Rows zurückzuliefern. Das kannst du machen, indem du statt des derzeit leeren Arrays diese Anzahl als Integer liefert.
Bei einem Insert sieht die Sachlage etwas komplexer aus. Wenn du immer nur einen Datensatz einfügst, interessiert dich vielleicht eher die LastInsertID. Wenn aber sowohl die Anzahl der eingefügten Datensätze als auch die LastInsertID interessiert, müssten diese beiden Informationen zurückgegeben werden. Tupel kennt PHP nicht, aber ein Array mit beiden Werten wäre nicht verkehrt.
Da db_query() allerdings ohne die Query zu analysieren nicht weiß, was der Aufrufer effektiv für Informationen braucht, wäre es sicher sinnvoll, ohne groß nachzudenken ein Array mit den beiden Informationen affected Rows und LastInsertID zurückzugeben.
[*] RUDI = Read, Update, Delete, Insert. Auch als CRUD bekannt (Create statt Insert).
echo "$verabschiedung $name";
Dürfte dann so richtig sein:
public static function db_query($sql, $asObject = false, $objectParams = null) {
$result = array();
if ($asObject) { // true oder string
if (is\_string($asObject)) {
$className = $asObject;
if (!class\_exists($className))
throw new Exception('class ' . $className . ' does not exist.');
} else { // kein Klassenname übergeben, Standard-Klasse verwenden lassen
$className = null;
$objectParams = null;
}
}
$mysqli = self::\_getConnection();// das ist eine private Methode, die mit ein mysqli-Objekt mit aktiver Verbindung gibt.
$mysqliResult = $mysqli->query($sql, MYSQLI\_USE\_RESULT);
# Query Fehlgeschlagen
if (!$mysqliResult){
throw new Exception("Query fehlgeschlagen <p>".$sql."</p>");
$result=false;
if (mysqli\_error($mysqli)) {
errorlog::getError(1, "MySQL Query-Error, vllt sind die Zugangsdaten falsch.<p>".$sql."</p>", mysqli\_error());
$result = false;
}
}
# Query nicht fehlgeschlagen - R
if ($mysqliResult instanceof mysqli\_result) {
if ($asObject) {
while ($row = $mysqliResult->fetch\_object($className, $objectParams))
$result[] = $row;
}else {
while ($row = $mysqliResult->fetch\_assoc())
$result[] = $row;
}
// wird unbedingt benötigt, wegen MYSQLI\_USE\_RESULT @see mysqli::query()
$mysqliResult->free();
} else {
# Betroffenen Datensätze
$arows=$mysqli->affected\_rows;
if($affectedRows == 0) # Query fehlgeschlagen
{
$result = array(false, 0, 0);
}
else # Query nicht fehlgeschlagen - UDI
{
$result = array(true, $affectedRows, $mysqli->insert\_id);
}
}
return $result;
}
echo $begrüßung;
Dürfte dann so richtig sein:
Ob etwas richtig ist oder nicht erfährt man durch Funktionstests. Ich mache diese nicht nur hinterher sondern laufend bei Code-Schreiben. Hast du für all deine Anwendungsfälle Beispiele erstellt und probiert ob sie ein richtiges Ergebnis liefern? Außerdem gibt es diverse Möglichkeiten, dass etwas schief läuft. Bitte überlege dir, welche Fehler auftreten können, versuch sie zu simulieren und schau dir an, ob die Reaktion darauf deinen Erwartungen entspricht.
$mysqli = self::\_getConnection();// das ist eine private Methode, die mir ein mysqli-Objekt mit aktiver Verbindung gibt.
Hier holen wir uns eine Connection. Ich gehe davon aus, dass diese Funktion so implementiert ist, dass sie im Fehlerfall eine Exception wirft. (Möglicherweise hab ich das bisher nicht erwähnt.) An dieser Stelle habe ich kein Auffangen der Exception eingebaut, weil ich nicht sehe, was man an dieser Stelle Sinnvolles mit der Exception anfangen kann. Verbindungsfehler kann man nicht überspielen, wenn man eine Query über die Verbindung absetzen will. Eine Fehlerbehandlung bringt an der Stelle nichts. Also wird die Exception an den Aufrufer dieser Methode durchgereicht.
Wenn die Verbindung nicht erstellt werden konnte gibt es hier einen Abbruch.
$mysqliResult = $mysqli->query($sql, MYSQLI\_USE\_RESULT); # Query Fehlgeschlagen if (!$mysqliResult){ throw new Exception("Query fehlgeschlagen <p>".$sql."</p>");
Zum Grundlagenwissen der OOP gehört auch das Wissen über die Arbeitsweise von Exceptions. Ein throw beendet die aktuelle Verarbeitung und setzt beim nächsten erreichbaren catch fort. Bitte informiere dich zu Exceptions. Der nachfolgende Code kann nicht ausgeführt werden, da er wegen der geworfenen Exception unerreichbar ist.
$result=false; if (mysqli\_error($mysqli)) { errorlog::getError(1, "MySQL Query-Error, vllt sind die Zugangsdaten falsch.<p>".$sql."</p>", mysqli\_error()); $result = false; }
Die Verbindung wurde in einem früheren Schritt aufgebaut. Wir sind hier bereits beim Abarbeiten der Query. Die Zugangsdaten können keine Ursache für eine nicht erfolgreiche Query sein, denn ohne eine Verbindung lohnt es sich nicht, eine Query zu starten.
Wenn ein Fehler aufgetreten ist und eine Meldung geloggt werden soll, nützen keine Spekulationen. Die Stelle, an der der Fehler auftrat und die vom System erzeugte Meldung sowie Begleitumstände (Variableninhalte) sind zur Fehlersuche interessant.
# Betroffenen Datensätze $arows=$mysqli->affected\_rows; if($affectedRows == 0) # Query fehlgeschlagen
Diese unterschiedlichen Variablennamen sollten bei einem Probelauf auffallen, denn dann sollte es eine E_NOTICE geben.
----------------
Nach dem, was ich bisher gesehen habe, hast du ehrgeizige Ziele, aber dir fehlen enscheidende Dinge zu deren Erreichen. Grundlagenwissen und ein Mindestmaß an Erfahrung mit dem Umgang der eingesetzten Werkzeuge sind Voraussetzungen zum Erfolg. Auch das Verständnis für Konzepte ist wichtig. Wann passiert was und welche Fehler können dabei auftreten. Ich tue mich schwer, dir eine Empfehlung zu geben, wie du die Defizite beseitigen kannst außer einem allgemeinen Lesen, Üben, Lesen, Üben, Üben, Üben.
Wenn die Möglichkeiten mitgelieferten API nicht ausreichen und man mehr Funktionalität und Komfort haben möchte, kann man auf die zur Genüge vorhandenen Datenbankabstraktionen zugreifen. Denn oft bieten diese Abstraktionen nicht nur eine einheitliche Schnittstelle zu verschiedenen Systemen (das braucht man weniger häufig als es immer als Vorteil hervorgehoben wird) sondern auch Mehrwert durch Funktionalität. Nimm dir lieber für den Anfang eines dieser fertigen Systeme, selbst wenn es PDO ist, und nimm dir außerdem ein Buch oder Tutorials zur OOP unter PHP, denn ohne diese Grundlagen kommen wir hier nicht wirklich weiter.
echo "$verabschiedung $name";