MB: Datenbank Verbindung über Klassen

nabend Community,

ich bin dabei über PDO eine Verbindungen zu Datenbank aufzubauen. Privat und rein zur übungszwecken. Ich habe mich immer grob das datenmodell gehalten.

Konfigurations Klasse -> Verbindungs Klasse -> Session ->User

//Bemerkung: die Pfeile entsprechen einer Vererbung
  • Was ist besser? Und wenn beide ihre vorzüge haben welche genau sind das?
class database extends PDO
{
  ...
  public function __construct() {
    parent::__construct( ... )
  }
}

oder der art...

class database
{
  ...
  public function __construct() {
    $ths->db = new PDO( ... );
  }
}
  • Warum solte man keinen konstruktor new verwenden sondern nur extends und parent::irgendwas.
  • Warum ist es nicht sinnvoll FINAL vor die konfiguration einer datenbankverbindung zusetzen wie
class cfg
{
  private
    $DB_DRV     = "mysql";
    //...
  public final function getDSN() {
    //return ...
  }
  public final function getUSER() {
    //return ...
  }
  public final function getPW() {
    //return ...
  }
}
  • warum meine ich mich erinnern zu können sollte man be einer Verbindung nicht Konstanten verwenden?

Ich hoffe meine Frage war verständlich, strukturiert und nicht zu viel auf einmal.

Grüße MB

  1. Tach!

    ich bin dabei über PDO eine Verbindungen zu Datenbank aufzubauen. Privat und rein zur übungszwecken. Ich habe mich immer grob das datenmodell gehalten.

    Konfigurations Klasse -> Verbindungs Klasse -> Session ->User
    
    //Bemerkung: die Pfeile entsprechen einer Vererbung
    

    Warum müssen die Konfigurationsdaten in einer Klasse sein? Warum muss die Datenbankklasse davon erben? Es reicht, wenn sie die Daten zur Verfügung gestellt bekommt und sie verwendet.

    Eine Session muss auch nicht von der Datenbank erben, wenn sie nur Verwender ist. Sie kann ihre Daten ja auch im Dateisystem ablegen und braucht dann einen anderen Persistierungsmechanismus. Sie mit der Datenbank fest zu koppeln, macht das nur unnötig schwer oder unmöglich.

    User ist üblicherweise ein einfaches Objekt. POJO (Plain Old Java Object) und POCO (Plain Old CLR Object) nennt man das beispielsweise in anderen Programmiersprachen. Für PHP wäre das dann POPO, aber das klingt irgendwie falsch. Jedenfalls ist es besser zur Verwaltung der Daten Dinge wie ein Repository und/oder einen Service zu verwenden. Die sind das Bindeglied zwischen den Daten und der verwendeten Persistierungsmethode (Methode im allgemeinen und nicht im OOP-Sinne).

    Es gibt zwar auch das Muster namens Active Record, aber das ist nicht besonders toll, weil dann die Datenobjekte immer die Persistierungsmethoden (hier im OOP-Sinne) mitschleppen, auch an Stellen, an denen man sie gar nicht braucht.

    • Was ist besser? Und wenn beide ihre vorzüge haben welche genau sind das?

    Kommt immer darauf an, was man erreichen möchte. Daumenregel: Vererbung verwendet man nur, wenn man etwas erweitern muss. Wenn man es lediglich verwendet, muss man es nicht erben, dann kann man es übergeben bekommen und sich eine Referenz darauf merken. Vererbung führt dazu, dass man starre Verbindungen herstellt und die Dinge immer größer und damit unhandlicher werden.

    • Warum solte man keinen konstruktor new verwenden sondern nur extends und parent::irgendwas.

    Wer sagt das?

    • Warum ist es nicht sinnvoll FINAL vor die konfiguration einer datenbankverbindung zusetzen wie

    Welchen Sinn hat es denn, an den Stellen final zu verwenden? Kennst du einen, der dich für diese konkrete Verwendung von der Notwendigkeit und Richtigkeit der Verwendung überzeugt? Wenn nicht, dann lass es weg.

    • warum meine ich mich erinnern zu können sollte man be einer Verbindung nicht Konstanten verwenden?

    Kommt auf das Ziel an. In einfachen Scripten spricht nicht wirklich was gegen ihre Verwendung. Allerdings verhindern sie oder erschweren massiv die Entwicklung nach dem TDD-Prinzip (test driven design). Beim TDD testet man nicht gegen eine richtige Datenbank, sondern eine simulierte, bespielsweise mit Mock-Objekten. Eine Datenbank ist eine Blackbox. Man kann da nicht testen, ob man die richtigen Werte übergeben hat oder ob man nur zufällig eine positive Rückmeldung bekommt. Das Mock-Objekt hingegen kann man untersuchen und so feststellen, dass Username und Passwort an den richtigen Stellen übergeben wurden.

    dedlfix.

  2. Konfigurations Klasse -> Verbindungs Klasse -> Session ->User

    Ein wirtschaftlicher Aspekt, seine Daten in Klassen zu organisieren ist der, dass eine Klasse den Speicherort abstrahiert.

    Das heißt am Beispiel einer Konfiguration: Dieser Hugo von Daten steckt nur deswegen in einer Instanz, weil es eine Instanz geben muss, die den Speicherort kennt.

    Oder für die Session: Dieses Array muss den Speicherort nur deswegen kennen, damit eine $session->write() weiß wo das $session-Objekt die Daten am Ende einer Session persistent macht.

    Und der User schließlich ist auch ein Objekt, weil persistente Daten dahinterstecken.

    Aufgrund einer solchen Herangehensweise ergibt sich auch die Klassenhierarchie. Eine spezielle Verbindungs-Klasse erübrigt sich, weil Config, Session, User selbst den Speicherort bestimmen und das unabhängig voneinander. So wird ein Data-Access-Layer für die Config austauschbar, ohne das ganze System umbauen zu müssen und sinngem. gilt das auch für alle anderen Klassen, die irgenwo die Daten speichern müssen (Dateisystem, Netzwerk, MySQL usw.).

    Für den User schließlich ergeben sich 2 Orte persistenter Daten: Einmal diejenigen die in der Session stecken (username, zeitstempel der Anmeldung, Gruppe, usw.) und zum Anderen sind es die Stammdaten (Name, Vorname, PLZ, Ort, Passwort....).

    Damit ein Programmierer nicht jedesmal nachgucken muss, wie die Datenstruktur in der Session aussieht, gibt ja die Möglichkeit, dem SessionObjekt Methoden zu verpassen. Und da könnte eine der Methoden $session->user() ein Array mit den Userdaten aus der Session liefern.

    Zwischen Config und Session sehe ich jedoch keine Notwendigkeit einer Klassenbeziehung.

    Nichts jedoch spricht dagegen, eine Klassenhierachie auf dem DAL abzu bilden, z.b. Config::File, Config::MySQL. Oder die Data-Abstraction erfolgt in der Klasse selbst und der Konstrukor entscheidet:

    tie %SESSION, 'Session', file => $sessionfilename;
    tie %SESSION, 'Session'  dbh  => $databasehandler;
    

    Zur Beschaffung des Database-Handler (PDO, DBH) reicht eine Methode. Ich greife da gerne auf meine Factory zurück: $dbh = $self->dbh(base => 'dbname'); wobei die Methode dbh() den Pfad zur Datei mit den Credentials kennt (host,port,user,pass stehen da drin so genügt die Angabe des Namen für die Datenbank).

  3. Servus MB,

    • Was ist besser? Und wenn beide ihre vorzüge haben welche genau sind das?
    class database extends PDO
    {
      ...
      public function __construct() {
        parent::__construct( ... )
      }
    }
    

    oder der art...

    class database
    {
      ...
      public function __construct() {
        $ths->db = new PDO( ... );
      }
    }
    

    Ich ziehe letztere Variante vor. Du kannst bei ihr selbst gestalten, wie die Klasse aussehen soll, was für Methoden zur Verfügung stehen, was für Parameter sie haben etc. Außerdem: solltest du mal eine Alternative zu PDO implementieren wollen, wirst du mit dem ersten Vorschlag keinen Spaß haben. Selbst ein Update von PDO könnte Probleme machen.

    • Warum solte man keinen konstruktor new verwenden sondern nur extends und parent::irgendwas.

    Die Frage ist merkwürdig.

    • Wenn ich ein Objekt von einer Klasse will, benutze ich new Klasse().
    • Wenn eine Klasse von einer anderen erben soll, benutze ich Klasse1 extends Klasse2.
    • Wenn ich in einer Klasse die statische Methode der Klasse benutzen will, von der geerbt wird, benutze ich parent::foo() (Syntaxfehler vorbehalten)

    Da gibts kein sondern.

    • Warum ist es nicht sinnvoll FINAL vor die konfiguration einer datenbankverbindung zusetzen wie

    Wenn du denkst, dass eine Methode so cool ist, dass keiner sie per Vererbung überschreiben darf, dann benutz final. Sinnvoll? Ansichtssache. Probiers aus.

    • warum meine ich mich erinnern zu können sollte man be einer Verbindung nicht Konstanten verwenden?

    Soll sich die Datenbank-Verbindung in der Anwendung ändern? Nö? Warum dann keine Konstante? Wie sagte noch Bubba in Forrest Gump:

    Konstanten sind die Früchte des Meeres. Du kannst sie am Spieß braten, backen, braten, auf den Grill tun, sautieren... Es gibt Konstanten-Kabob, Konstanten-Creole, Konstanten-Gumbo. In der Pfanne gebraten, frittiert. Es gibt Konstanten mit Bananen, Bohnenkonstanten, Kokosnusskonstanten, Pfefferkonstanten, Konstantensuppe, Konstanteneintopf, Konstantensalat, Konstanten mit Kartoffeln, Konstantenburger, Konstantensandwich... Das wars, glaube ich.

    ;)

    Ernsthaft: Konstanten gibt es nicht umsonst. Benutze sie, sammle Erfahrungen. Entwickle ein paar Scripte und setze sie ein. Denk drüber nach, ob der Einsatz so sinnvoll ist/war.

    ciao

    --
    "Sir, we are surrounded" - "Excellent, we can attack in any direction!"
    1. Lieber henman,

      class database
      {
        ...
        public function __construct() {
          $this->db = new PDO( ... );
        }
      }
      

      [vorzuziehen weil] Du kannst bei ihr selbst gestalten, wie die Klasse aussehen soll, was für Methoden zur Verfügung stehen, was für Parameter sie haben etc.

      es gibt noch einen technischen Vorteil bezüglich persistent connections und abgeleiteter Klassen. Einem User-Kommentar zufolge kann es Probleme geben, wenn man persistente Verbindungen nutzen möchte und dabei eine von PDO abgeleitete Klasse nutzt. In obigem Beispiel wird ein "echtes" PDO-Objekt verwendet, sodass damit eine persistente Verbindung - zumindest laut eben erwähntem Kommentar - keine Probleme bereiten sollte.

      Liebe Grüße,

      Felix Riesterer.

      1. Tach!

        es gibt noch einen technischen Vorteil bezüglich persistent connections und abgeleiteter Klassen. Einem User-Kommentar zufolge kann es Probleme geben, wenn man persistente Verbindungen nutzen möchte und dabei eine von PDO abgeleitete Klasse nutzt. In obigem Beispiel wird ein "echtes" PDO-Objekt verwendet, sodass damit eine persistente Verbindung - zumindest laut eben erwähntem Kommentar - keine Probleme bereiten sollte.

        Einen umgangenen Fehler im verwendeten System als Vorteil einer bestimmten Vorgehsweise zu bezeichnen ist etwas gewagt, finde ich. Fehler gehören beseitigt, das Umgehen sollte nur eine Notlösung sein. Die eigentliche Frage ist aber, ob persistente Verbindungen für einen konkreten Anwendungsfall wirklich sinnvoll sind oder nicht. Nur wenn man die Umgebung selbst kontrollieren kann, PHP als Apache-Modul und nicht als FCGI verwendet, und eine hohe Last auf dem Datenbank-Server liegt, dann spart man etwas Overhead für den Verbindungsaufbau. (Der ist bei MySQL aber schon ziemlich schnell.) Für die überwiegende Mehrzahl an Webanwendungen sind persistente Verbindungen kein Thema. - Und wenn man ein Framework schreibt, das möglichst auf vielen Konstellationen laufen soll, dann ist der kleinste gemeinsame Nenner ebenfalls, keine persistenten Verbindungen zu haben.

        dedlfix.