Impressum · Kontakt · Hilfe
Besucher online · Mitglieder



Portal > Foren > PHP > PHP-Programmierung > Datenbank - Abstraktionsklasse
Antwort
 
Themen-Optionen
Alt 12.05.2007, 19:11   Nach oben    #1
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard Datenbank - Abstraktionsklasse

Hallo zusammen,

ich weiß, ich erfinde das Rad neu, aber dabei lernt man ja am besten ..

Also:
Ich möchte eine DB-Klasse schreiben. Dazu habe ich erstmal eine abstrakte Klasse definiert:
PHP-Code:
abstract class database {
  
  private 
$host;
  private 
$db;
  private 
$user;
  private 
$pass;
  
  private 
$connection;
  private 
$result;
  
  const 
DB_NUM   1;
  const 
DB_ASSOC 2;
  const 
DB_BOTH  3;
  
  
  public function 
__construct($host NULL$db NULL$user NULL$pass NULL) {
    if(
$host !== NULL$this->host $host;
    if(
$db   !== NULL$this->db   $db;
    if(
$user !== NULL$this->user $user;
    if(
$pass !== NULL$this->pass $pass;
    
$this->connect();
  }
  
  public function 
__destruct() {
    
$this->disconnect();
  }
  
  
  abstract public function 
connect();
  abstract public function 
disconnect();
  
  abstract public function 
query($query);
  
  abstract public function 
escapeStr($var);
  
  abstract public function 
getResult(); // return all results as multi-dimensional array
  
abstract public function getRow($as self::DB_ASSOC); // return result (one row) als one-dimensional array
  
abstract public function numRows();
  abstract public function 
freeResult();
  
  abstract public function 
errstr();
  abstract public function 
errnum();
  
  abstract public function 
conf($var$value NULL); // gets $var / sets $var to $value
  

Nun meine Frage: Wie findet ihr die Struktur? Fehlt etwas? Ist etwas unnötig?


MfG,
FloB
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 12.05.2007, 20:27   Nach oben    #2
BIN EIN KRASSA HELD!!!111
 
Benutzerbild von robo47
 
Registriert seit: 02.06.2005
Ort: weiher im tiefsten Odenwald
Beiträge: 1.184
Standard

$this->connect();
im Konstruktor bringt nicht viel wenn die kompletten parameter nicht übergeben wurden!

Wenn getRow die möglichkeit der entscheidung hat ob assoc, num oder object, dann sollte man das auch bei getResults wählen können ob mein Array mit assoziativen oder numerischen Arrays oder mit Objekten will.

eventuell noch ne methode für affected rows ? oder fasst du das unter num_rows zusammen ?

last-insert-id als methode ? kann man auch via query realisieren ...

nur so als anregungen.
robo47 ist gerade online  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 12.05.2007, 22:23   Nach oben    #3
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Die "Parameter" werden ja als Klassenattribute gespeichert, connect() greift auf diese zu (wenn man mehrere DB-Verbindungen zu versch. DBs aufbauen will, nimmt man ja eh ein neues Objekt).

DB_OBJ kann ich noch einbauen, dachte mir aber eigentlich, dass Objekte langsamer als Arrays sind .. immer perfomant denken .
Bei getResult() wird noch ein DB_NUM kommen.

affected rows .. hm .. eigentlich schon zusammenfassen .. ich kann ja bei mysql_query() auf true überprüfen, wenn ich affected_rows() nehmen will, anosnten num_rows().

Alles andere ist ja auch per Query möglich.


Aber sonst ist das OK so?

Eine Frage hab ich noch: Wenn ich den Konstruktor der Kindklasse dann aufrufe (z.B. new db_mysql($host, ..)), werden dann die Paramter in der dabase-(Abstraktions-)Klasse gespeichert oder in der Kindklasse?
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 13.05.2007, 18:00   Nach oben    #4
Entwickler
 
Benutzerbild von dr.e.
 
Registriert seit: 05.02.2007
Ort: München
Beiträge: 115
Standard

Hallo FloB,

zieh dir mal unter http://christian.zierpflanzenberatun.../apps_core.chm die CHM-Dokumentation und schau dir mal den MySQLHandler an. Vielleicht ist das eine Anregung für dich...
__________________
Grüße,
Dr.E.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Have a look at http://www.adventure-php-framework.org!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 13.05.2007, 20:54   Nach oben    #5
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Danke .. kann ich sicher noch was übernehmen, wobei das für meinen Geschmack zu viel Funktionen sind ..
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 13.05.2007, 23:06   Nach oben    #6
Entwickler
 
Benutzerbild von dr.e.
 
Registriert seit: 05.02.2007
Ort: München
Beiträge: 115
Standard

Hallo FloB,

zu viele private, oder zu viele öffentliche?
__________________
Grüße,
Dr.E.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Have a look at http://www.adventure-php-framework.org!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.05.2007, 14:11   Nach oben    #7
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Gute Frage ..

Nun, es ist halt vieles abgedekt, z.B. wird automatisch $_lasetInsertID erzeugt - in den wenigsten Fällen braucht man das ...
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.05.2007, 15:28   Nach oben    #8
Entwickler
 
Benutzerbild von dr.e.
 
Registriert seit: 05.02.2007
Ort: München
Beiträge: 115
Standard

Hallo FloB,

wenn man doch wiederverwendbare und generische Abstraktions-Schichten designed, muss man alle benötigten Fälle abdecken und das ist hier getan...
__________________
Grüße,
Dr.E.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Have a look at http://www.adventure-php-framework.org!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.05.2007, 19:22   Nach oben    #9
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Das überzeugt mich - zumindest teilweise .

Werd mal drüber nachdenken.

Danke für deine Hilfe!
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.05.2007, 11:22   Nach oben    #10
Erfahrener Benutzer
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 789
Standard

In meiner/meinen MySql-Klassen erwartet query() zwei Parameter:

1. die Query mit Platzhaltern (in der ersten Version nur %s, in der zweiten Version benannte Variablen: %id%, %author% etc.);

2. ein Array mit den Werten, die diese Platzhalter ersetzen sollen (im ersten Fall ein indiziertes Array mit den Werten in der richtigen Reihenfolge, im zweiten eben eine assoziatives Array).

wenn du das nicht so machst (bzw. keine andere Lösung findest), musst du ja immer außerhalb der MySQL-Klasse mysql_real_escape_string() verwenden und das ist ja nicht der Sinn einer Kapselung in einer Klasse*). Letztlich geht es ja auch darum, diese Klasse durch beliebige andere SQL-Klassen austauschen zu können. Daher noch drei Punkte:

- Bennene die Klasse nicht "database", sondern Database_MySQL, MySqlConnector, oder sonstwie.
- Schreibe ein Interface IDatabase oder so und lass die Klasse dieses implementieren.
- Erkläre mal, warum die Klasse abstrakt sein soll. Da gibts eigentlich nichts zu erweitern, sondern eher eben durch andere Klassen auszutauschen (MySqliConnector, PdoDatabase etc.).

*) Seh grad, dass du eine Funktion zum Escapen anbietest. Ist dennoch einiges einfacher, wenn die du Query und Werte getrennt übergibst!

Basti
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.05.2007, 14:05   Nach oben    #11
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Ich habe eigentlich nur aus dem Grund eine Abstraktionsklasse geschrieben, um den Kon- und Destruktor sowie die Variablen als "private" zu definieren. Alles andere sind ja public's, deswegen werden die eh von den Kindklassen überschrieben.

Ich wollte von Anfang an festlegen, dass eine Verbindung nur anhand der Attribute der Klasse aufgebaut werden kann, also dass die Verbindungsdaten nicht als Parameter für connect() übergeben werden sollen (dürfen).

Meinst du, ich hätte eher ein Interface basteln sollen?

Ich habe mir bei der Planung gedacht, dass es eine Kindklasse mit dem Namen db_sql gibt, die dann entweder PDO nutzt, oder weitere Kindklassen (mit MySQL o.ä.) aufruft.


Eine automatische Behandlung im Query find ich gut, aber manchmal möchte ich nicht unbedingt einen String escapen ...
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.05.2007, 14:17   Nach oben    #12
Erfahrener Benutzer
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 789
Standard

Zitat:
Zitat von FloB Beitrag anzeigen
Ich habe eigentlich nur aus dem Grund eine Abstraktionsklasse geschrieben, um den Kon- und Destruktor sowie die Variablen als "private" zu definieren. Alles andere sind ja public's, deswegen werden die eh von den Kindklassen überschrieben.

Ich wollte von Anfang an festlegen, dass eine Verbindung nur anhand der Attribute der Klasse aufgebaut werden kann, also dass die Verbindungsdaten nicht als Parameter für connect() übergeben werden sollen (dürfen).

Meinst du, ich hätte eher ein Interface basteln sollen?
Die Frage ist halt, was letztlich übrig bleibt. Einer PDO-Klasse übergibst du ja einen String mit den Verbindungsdaten, da kannst du den Konstruktor also schonmal vergessen und die privaten Eigenschaften brauchst du dann letztlich auch nicht. Und, ja, das beenden der Verbindung würde natürlich in eine Basisklasse passen. Je nach Anwendung lässt sich sowas aber auch leicht von außen steuern.

Zitat:
Eine automatische Behandlung im Query find ich gut, aber manchmal möchte ich nicht unbedingt einen String escapen ...
Das ist dann ja kein Problem. Hierzu schreibst du die Werte einfach direkt rein:
PHP-Code:
<?php

class MyDao extends Dao
{
    public function 
getSomething($iId$sName)
    {
        
$sQuery "SELECT * FROM `table` WHERE id = $iId AND name = `%name%`";
        return 
$this->query($sQuery, array('name' => $sName));
    }
}

Basti
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 15.05.2007, 14:33   Nach oben    #13
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Nun, in der connect()-Funktion der Kindklasse db_sql könnte der Verbindungsaufbau mit PDO so aussehen:
PHP-Code:
$conn = new PDO($this->drv.':host='.$this->host.';dbname='.$this->db$this->user$this->pass); 
Im Konstruktor werden die Variablen dann definiert.

Privat habe ich die Variablen aus dem Grund definiert, um Sicherheit zu gewährleisten. Wenn jetzt ein 3rd-Party-Modul einfach database::pass ausliest und an den Programmierer schickt, hat der User den Salat.

*TODO: in der Abstraktionsklasse __get() definieren (final) und false zurückgeben / Exception werfen.
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.05.2007, 10:21   Nach oben    #14
Erfahrener Benutzer
 
Registriert seit: 04.01.2006
Ort: Kassel
Beiträge: 789
Standard

Huch? Und wo kommen die Verbindungsdaten her? Was ist mit var_dump()? Was mit den Reflection-Klassen?

Basti
Basti ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.05.2007, 14:50   Nach oben    #15
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Die Verbindugsdaten werden direkt in die Datei geschrieben - bei der Installation. var_dump() muss ich mir anschauen, denke aber, dass man das per private eben umgehen kann.

Die Reflection-Klassen muss ich mir mal anschauen ..
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.05.2007, 22:02   Nach oben    #16
Entwickler
 
Benutzerbild von dr.e.
 
Registriert seit: 05.02.2007
Ort: München
Beiträge: 115
Standard

Zitat:
Die Verbindugsdaten werden direkt in die Datei geschrieben - bei der Installation.
Das ist ein Design-Fehler. Verbindungsdaten MUSS man konfigurierbar machen.
__________________
Grüße,
Dr.E.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Have a look at http://www.adventure-php-framework.org!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 16.05.2007, 23:50   Nach oben    #17
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

Ja - wenn die Datei beschreibbar ist. Diesen Design-Fehler nehme ich in Kauf, solange es der Sicherheit dient.

Natürlich kann man immernoch eine andere Verbindung aufbauen - dazu eine neue Instanz der Klasse anlegen (Verbindungsdaten werden an Konstruktor übergeben, der "ändert" sie). Nur kann man die Standard-Verbindungsdaten nicht erfragen!
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 17.05.2007, 00:56   Nach oben    #18
Entwickler
 
Benutzerbild von dr.e.
 
Registriert seit: 05.02.2007
Ort: München
Beiträge: 115
Standard

Hallo FloB,

in "meiner Welt" wird die MySQL-Abstraktions-Schicht mit der Methode $this->__getServiceObject() initialisiert und erhält dabei vom serviceManager automatisch den Context der Applikation. Mit Hilfe dieses Contextes kann die MySQL-Klasse dann die zugehörige Konfiguration für die Verbindungsdaten und andere Einstellungen laden. Da der Context einer Applikation jeweils für den kompletten Objektbaum zentral in der index.php geändert werden kann ist man hier absolut flexibel. Möchte man eine andere Verbindung als die Standard-Verbindung aufbauen, kann man einfach einen neuen MySQL-Treiber mit einem anderen Context erstellen.

Die Möglichkeit über die Änderung der Zugangsdaten im Konstruktor ist zwar niicht verkehrt, jedoch behindert diese Tatsache dich, den Treiber singleton zu instanziieren um z.B. bessere Performance erziehlen zu können.
__________________
Grüße,
Dr.E.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Have a look at http://www.adventure-php-framework.org!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 17.05.2007, 01:33   Nach oben    #19
Erfahrener Benutzer
 
Registriert seit: 12.06.2006
Beiträge: 189
Standard

So firm bin ich in OOP nicht, dass ich alles in deinem Beitrag verstehen würde ..

Ich will nur aus Sicherheitsgründen die (Standard-)Verbindungsdaten in der Klasse privat speichern, sodass ein 3rd-Party-Modul diese nicht auslesen kann und sonst etwas anstellen kann.

Bisher hab ich es so gesehen, dass die DB-Daten einmal eingetragen werden und dann nicht mehr verändert werden - Umstrukturierungen / Umzug sind Ausnahmen.

Aber meint ihr, das wäre egal? Könnte man die Sicherheit irgendwie anders lösen, also praktisch in der Config-Klasse überprüfen, ob die abrufende Klasse eine Instanz von soundso ist? Wie geht das, mit instance_of()?
FloB ist offline  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 17.05.2007, 09:42   Nach oben    #20
BIN EIN KRASSA HELD!!!111
 
Benutzerbild von robo47
 
Registriert seit: 02.06.2005
Ort: weiher im tiefsten Odenwald
Beiträge: 1.184
Standard

das klingt ja so, wie wenn du wild-fremden php-code zusätzlich zu deinem laufen lässt. das 3rd-Party-Modul, das deine Daten will um sie weiterzuversenden bekommt sie recht einfach indem es die Datei via fopen öffnet, oder var_dump nutzt oder sonst irgendwas und wenn es was böses in der datenbank machen will, nutzt es einfach die instanz deiner datenbankklasse.
robo47 ist gerade online  
Add Post to del.icio.usBookmark Post in TechnoratiDiesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Antwort

Lesezeichen