2008-09-10 3 views
2

Im Folgenden stelle ich drei Optionen vor, um meinen Datenbankzugriff zu vereinfachen, wenn nur eine einzige Verbindung involviert ist (dies ist häufig der Fall für die Web-Apps, an denen ich arbeite).Beste Möglichkeit zum Ausblenden von DB-Verbindungscode in PHP5 für Apps, die nur eine Verbindung benötigen?

Die allgemeine Idee ist, die DB-Verbindung transparent zu machen, so dass es verbindet, wenn mein Skript zum ersten Mal eine Abfrage ausführt, und dann verbunden bleibt, bis das Skript beendet wird.

Ich würde gerne wissen, welche Sie denken, ist die beste und warum. Ich kenne die Namen von Designmustern, denen diese passen könnten, so sehr, dass ich sie nicht verwende. Und wenn es eine bessere Möglichkeit gibt, dies mit PHP5 zu tun, bitte teilen.

Um eine kurze Einführung zu geben: Es gibt eine DB_Connection-Klasse, die eine Abfrage-Methode enthält. Dies ist eine Drittanbieter-Klasse, die ich nicht kontrollieren kann und deren Schnittstelle ich für dieses Beispiel vereinfacht habe. In jeder Option habe ich auch ein Beispielmodell für eine imaginäre DB "items" -Tabelle bereitgestellt, um einen Kontext zu geben.

Option 3 ist diejenige, die mir die Schnittstelle bietet, die ich am meisten mag, aber ich denke nicht, dass es praktisch ist.

Ich habe die Vor- und Nachteile (die ich sehen kann) von jedem in den Kommentaren unten beschrieben.

Im Moment lehne ich mich Richtung Option 1, da die Last auf meine DB-Wrapper-Klasse statt auf die Modelle gelegt wird.

Alle Kommentare erwünscht!

Hinweis: Aus irgendeinem Grund zeigt die Stack Overflow-Vorschau eine codierte HTML-Entität anstelle von Unterstrichen. Wenn die Post so kommt, bitte beachten Sie dies.

<?php 

/** 
* This is the 3rd-party DB interface I'm trying to wrap. 
* I've simplified the interface to one method for this example. 
* 
* This class is used in each option below. 
*/ 
class DB_Connection { 
    public function &query($sql) { } 
} 

/** 
* OPTION 1 
* 
* Cons: Have to wrap every public DB_Connection method. 
* Pros: The model code is simple. 
*/ 
class DB { 
    private static $connection; 
    private static function &getConnection() { 
     if (!self::$connection) { 
      self::$connection = new DB_Connection(); 
     } 
     return self::$connection; 
    } 
    public static function &query($sql) { 
     $dbh = self::getConnection(); 
     return $dbh->query($sql); 
    } 
} 

class Item { 
    public static function &getList() { 
     return DB::query("SELECT * FROM items"); 
    } 
} 

/** 
* OPTION 2 
* 
* Pros: Don't have to wrap every DB_Connection function like in Option 1 
* Cons: Every function in the model is responsible for checking the connection 
*/ 

class DB { 
    protected static $connection = null; 
    public function connect() { 
     self::$connection = new DB_Connection(); 
    } 
} 

class Item extends DB { 
    public static function &getList() { 
     if (!self::$connection) $this->connect(); 
     return self::$connection->query("SELECT * FROM items"); 
    } 
} 

/** 
* OPTION 3 
* 
* Use magic methods 
* 
* Pros: Simple model code AND don't have to reimplement the DB_Connection interface 
* Cons: __callStatic requires PHP 5.3.0 and its args can't be passed-by-reference. 
*/ 
class DB { 
    private static $connection = null; 

    public static function &getConnection() { 
     if (!self::$connection) { 
      self::$connection = new DB_Connection(); 
     } 
     return self::$connection; 
    } 

    public static function __callStatic($name, $args) { 
     if (in_array($name, get_class_methods('DB_Connection'))) { 
      return call_user_func_array(
       array(self::getConnection(), $name), $args); 
     } 
    } 
} 

Antwort

1

Basierend auf Ihren oben genannten Beispielen, würde ich sagen, die Option 1 ist die beste - Einfachheit immer gewinnt, und Sie können eine ausgefallene Verbindung unterschiedlich behandeln je nach Methode (möchten Sie vielleicht anders für eine gespeicherte Prozedur fehlschlagen Aufruf als ein einfaches SELECT zum Beispiel).

1

Semantisch gesprochen, denke ich, Option 1 macht am meisten Sinn, wenn Sie DB als Ressource behandeln, dann ist DB_Connectioin ein Objekt, das es verwendet, aber nicht unbedingt das Objekt selbst.

Allerdings warne ich einige Dinge davor. Lassen Sie Ihre DB-Klasse nicht alle statischen Methoden verwenden, da dies Ihre Fähigkeit, Ihren Code zu testen, stark beeinträchtigt. Betrachten Sie stattdessen eine sehr einfache Inversion des Steuercontainers wie folgt:

class DB { 
    private $connection; 
    public function &query($sql) { 
     return $connection->query($sql); 
    } 
    public __construct(&$db_connection) { 
     $this->connection = $db_connection; 
    } 
} 

class Item { 
    public function &getList() { 
     return ResourceManager::getDB()->query("SELECT * FROM items"); 
    } 
} 

class ResourceManager { 
    private $db_connection; 
    private function &getDbConnection() { 
     if (!$this->connection) { 
      $this->connection = new DB_Connection(); 
     } 
     return $this->connection; 
    } 
    private $db; 
    public static function getDB() { 
     if(!$this->db) $this->db = new DB(getDbConnection()); 
    return $this->db; 
} 

Es gibt erhebliche Vorteile. Wenn Sie nicht möchten, dass DB als Singleton verwendet wird, nehmen Sie einfach eine Änderung an ResourceManager vor. Wenn Sie entscheiden, dass es kein Singleton sein soll - machen Sie die Modifikation an einem Ort. Wenn Sie eine andere DB-Instanz basierend auf einem bestimmten Kontext zurückgeben möchten, ist die Änderung ebenfalls nur an einer Stelle möglich.

Jetzt, wenn Sie Item in Isolation von DB testen möchten, erstellen Sie einfach eine SetDb ($ db) -Methode in ResourceManager und verwenden Sie es, um eine gefälschte/Mock-Datenbank (simplemock wird Ihnen in dieser Hinsicht gut dienen).

Zweitens - und das ist eine weitere Modifikation, die dieses Design erleichtert - Sie möchten vielleicht nicht Ihre Datenbankverbindung die ganze Zeit offen halten, es kann am Ende mit weit mehr Ressourcen als nötig sein.

Schließlich, wie Sie erwähnen, dass DB_Connection andere Methoden nicht gezeigt hat, wie es scheint, die es vielleicht als einfach für mehr verwendet werden, wobei eine Verbindung aufrechterhalten wird. Da Sie sagen, Sie haben keine Kontrolle darüber, könnte ich empfehlen eine Schnittstelle aus es der Methoden extrahieren, die Sie kümmern sich um DO und eine MyDBConnection macht sich DB_Connection Klasse, die Ihre Schnittstelle implementiert. Nach meiner Erfahrung wird so etwas auch Schmerzen lindern.