PHP - SQL Basics & Styles
am 07.07.2005 14:20:08 von steffen horstHallo,
ich bin noch ein bisschen ungeübt in der Kombination von Datenbanken
und PHP. Für eine neue, etwas größere private Homepage würde ich nun
gerne alle dynamischen Daten in einer Datenbank ablegen. Nun steh ich
vor der Frage, wie die Datenbank-Klassen am besten realisiert werden
können. Lösungen hab ich für alles, jedoch würde es mich sehr
interessieren, welche Methodiken sich bewähren werden, bzw. was Euch
am genehmsten erscheint - erfahrungsgemäß. Als Beispiel nehm ich mal
eine Artikel-Tabelle.
1. SELECTs
============================================================ ======
1a. Für die auszulesenden Daten existiert eine PHP-Klasse. Somit
sollte beim Abfragen der Datenbank ein Objekt-Array erstellt und
zurückgegeben werden.
Beispiel:
Abfrage: SELECT id, name, price FROM article
Ergebnis: Array (Article-Object #1, Article-Object #2)
Lösung: Eine Datenbank-Klasse stellt eine Methode zur Verfügung, die
anhand der übergebenen QUERY die entsprechenden Datensätze ausliest,
Objekte erstellt und in einem Array zurückliefert.
Fragen:
- Sollte in jedem Script die komplette Abfrage angegeben werden? Also:
$articlearr = DB::singleton()->getArticleList('
SELECT id, name, price
FROM article
');
Nachteil: Man hätte in vielen Scripten dieselbe Abfrage. Oder ist es
besser, in der Datenbank-Klasse Methoden wie
function getArticleArray($where_clause = 1);
zur Verfügung zu stellen? Dies hätte wiederum den Nachteil, weniger
Flexibilität bei der Abfrage zu haben.
- Ist für den häufigen Fall, dass ein *bestimmter* Artikel z.B. unter
Angabe seiner id abgerufen wird, eine eigene Methode sinnvoll? Etwa:
$article = DB::singleton()->getArticleById($id);
------------------------------------------------------------ ------
1b. Es gibt *keine* Klasse für die auszulesenden Datensätze. Die
auszulesenden Datensätze müssen deshalb in einem (assoziativen) Array
gespeichert werden.
Beispiel:
Abfrage: SELECT id, name, price FROM article
Ergebnis: Array(Array([id] = ..., [name] = ...), Array([id] = ...))
Fragen:
- Ist mysql_unbuffered_query() dann die geeignete Methode?
- Wie oben: Sollte die komplette Query in jedem Script angegeben
werden oder ist es sinnvoller, die Querys in den Datenbank-Klassen zu
definieren?
- Und auch: Was ist sinnvoll, wenn nur *ein* bestimmter Datensatz
gesucht wird? Eine eigene Methode, oder spart man sich diese und
greift stattdessen mittels reset() auf das erste Element zu? Wäre dann
z.B.:
$articlearr = reset(DB::singleton()->getArticles("WHERE id = $id"));
$articlename = $articlearr['name'];
------------------------------------------------------------ ------
1c. Gesucht ist EIN Wert einer bestimmten Zeile und Spalte. Die Zeile
wird dabei mittels primary key (hier id) angegeben und der Spaltenname
der Funktion übergeben. D.h.
Beispiel:
Abfrage: SELECT name FROM article WHERE id = 1
Ergebnis: "Seidige Handcreme"
Dies kann so realisiert werden:
$name = $DB::singleton()->getField('name', 'article', 'id=1');
oder mit
$article = reset($DB::singleton()->get('
SELECT name
FROM article
WHERE id = 1
');
$name = $article['name'];
2. Manipulationen
============================================================ ======
Auch hier wieder dieselbe Frage: Ist es schlau, INSERT, DELETE,
UPDATE-Anfragen jeweils im Script zu definieren oder sollte auch für
alle Manipulationen eigene Methoden in den Datenbank-Klassen
geschrieben werden?
3. Aktueller Stand
==================
Im Moment bin ich auf folgendem Standpunkt:
a. Alle SQL-Statements kommen in das jeweilige Script. Dadurch hat man
eine große Flexibilität und kann sich immer in SQL üben :) Falls sich
allerdings Tabellen ändern, gibts einen Haufen Arbeit.
b. Alle DB-Methoden liefern Arrays zurück. Die Scripte verwenden
reset(), wenn sie nur ein bestimmtes Element (z.b. id=1) benötigen.
Dadurch erhält man eine einheitliche Schreibweise. Nachteil ist
allerdings ein kleiner Overhead, wenn genau ein Wert (s. 1c) gesucht
ist. Dafür ist vielleicht eine Hilfsmethode angebracht.
$name = DB::singleton()->getField('name', '
SELECT name
FROM article
WHERE id = 1
');
c. Existieren PHP-Klassen für die Daten, erzeugt die Datenbank-Klasse
die Objekte und liefert ein Objekt-Array zurück. Beispiel-Aufruf:
DB::singleton()->getObjectArray('Article', '
SELECT *
FROM article
WHERE id < 3
');
Rückgabe: Array(Object id #1, Object id#2, ...);
Die DB-Klasse könnte sogar automatisch alle Spaltennamen durchgehen
(id, name, price) und versuchen, diese in einer neu erzeugten
Article-Instanz zu setzen. Also etwa so:
// Für alle Zeilen:
$article = new Article();
foreach ($queryresult as $name => $value)
{
// Wenn die Eigenschaften public sind oder bei __set()
$article->$name = $value;
// Wenn es Setter gibt:
$func = "set$name";
$article->$func($value);
// Oder man leitet die entsprechenden Klassen von einem
// DBObjekt ab und definiert dort eine Methode set($var, $val)
$article->set($name, $value)
}
Damit erklärt sich auch das eigentlich zu vermeidende SELECT *: Auf
diese Weise kann die Article-Klasse erweitert werden, wobei nur die
Tabelle in MYSQL erweitert werden muss. (Je nach Geschmack müsste die
Klassendefinition angepasst werden - ginge allerdings auch
automatisch). Die Datenbank-Klasse kann auf diese Weise aber in jedem
Fall unberührt bleiben.
d. Gibt es keine PHP-Klassen, wird ein Array mit assoziativen Arrays
zurückgegeben. Etwa so:
DB::singleton()->get('
SELECT *
FROM article
WHERE id < 3
');
Rückgabe:
Array(
Array(
[id] = 1,
[name] = ...,
[price] = ...
)
Array(
[id] = 2,
[name] = ...,
[price] = ...
)
)
e. Für Manipulationen gibt es eine Methode, die eine Query ausführt
und die Rückgabe unbearbeitet zurückliefert. Also:
DB::singleton()->set('
INSERT INTO article (id, name, price)
VALUES ('', '...', '...')
');
Rückgabe:
TRUE oder FALSE.
Das wärs. Danke für alle Antworten / Meinungen / Eindrücke
schöne grüße,
steffen