PHP - SQL Basics & Styles

PHP - SQL Basics & Styles

am 07.07.2005 14:20:08 von steffen horst

Hallo,

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

Re: PHP - SQL Basics & Styles

am 04.08.2005 15:35:22 von Jan Klettke

steffen horst schrieb:
> Hallo,
>
> 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

Moin Steffen,

da ich auch noch etwas Newbie bin, nur zu der Frage mit der sich laufend
wiederholenden Abfrage ein Kommentar. Warum bindest Du diesen Part nicht
einfach über ein Include ein? Das hat den Vorteil, daß die Abfrage nur
an einer Stelle erstellt wird und so an jeder Stelle verfügbar ist.

Herzliche Grüße

Jan