Frage

Ich denke PDO der Verwendung in allen meinen zukünftigen Webapp. Zur Zeit (mit, was ich von SO bisher gelernt haben), was ich in meiner Website Datenbank-Verbindung zu handhaben ist eine Singleton-Klasse wie folgt aus:

class DB {

    private static $instance = NULL;
    private static $dsn      = "mysql:host=localhost;dbname=mydatabase;";
    private static $db_user  = 'root';
    private static $db_pass  = '0O0ooIl1';

    private function __construct() 
    {

    }
    private function __clone()
    {

    }   
    public static function getInstance() {

        if (!self::$instance)
        {           
            self::$instance = new PDO(self::$dsn, self::$db_user, self::$db_pass);
            self::$instance-> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }
}

und eine andere Datei (functions.php) mit inhaltsspezifischen Funktionen suchen genau wie diese:

function get_recent_activities ()
{    
    try
    {    
        $db = DB::getInstance();
        // --prepare and execute query here, fetch the result--
        return $my_list_of_recent_activities;
    }
    catch (PDOException $e)
    {
        return "some fail-messages";
    }
}
...

was bedeutet, dass ich die try .. catch Teil in alle Funktionen wiederholen.

Meine Fragen sind:

  1. Wie soll ich machen, dass effizienter? (Z. B. mit nicht try..catch in allen Funktionen zu wiederholen, und dennoch in der Lage verschiedene zurückzukehren „Fail-Meldung“ auf jedem)
  2. Ist das schon eine gute Praxis? Ich bin noch neu bei PDO und OOP (noch viel zu lernen), so (wie jetzt), kann ich nicht wirklich irgendwelche Nachteile oder Dinge sehen, die dort verbessert werden können.

Es tut mir leid, wenn das unklare oder zu lang erscheint. Vielen Dank im Voraus.

War es hilfreich?

Lösung

Ihre Implementierung ist ganz gut, und es wird sehr gut für die meisten Zwecke arbeiten.

Es ist nicht notwendig, jede Abfrage in einem try / catch-Block zu setzen, und in der Tat in den meisten Fällen Sie wollen eigentlich nicht zu. Der Grund dafür ist, dass, wenn eine Abfrage eine Ausnahme erzeugt, es ist das Ergebnis einer fatalen Problem wie ein Syntaxfehler oder ein Datenbankproblem, und das sind nicht Probleme, die Sie für mit jeder Abfrage werden Buchhaltung sollten, die Sie tun.

Zum Beispiel:

try {
    $rs = $db->prepare('SELECT * FROM foo');
    $rs->execute();
    $foo = $rs->fetchAll();
} catch (Exception $e) {
    die("Oh noes! There's an error in the query!");
}

Die Abfrage wird hier entweder richtig funktionieren oder nicht funktionieren. Die Umstände, unter denen es würde nicht funktionieren sollen immer nicht mit einer gewissen Regelmäßigkeit auf einem Produktionssystem auftreten, so dass sie keine Bedingungen, die Sie hier überprüfen sollten. Dabei tatsächlich kontraproduktiv ist, weil die Benutzer eine Fehlermeldung erhalten, die sich nie ändern wird, und Sie keine Ausnahmemeldung erhalten, die Sie für das Problem aufmerksam machen würde.

Stattdessen schreiben Sie einfach dies:

$rs = $db->prepare('SELECT * FROM foo');
$rs->execute();
$foo = $rs->fetchAll();

Im Allgemeinen ist die einzige Zeit, die Sie wollen werden, um eine Abfrage Ausnahme abfangen und behandeln ist, wenn man etwas anderes tun will, wenn die Abfrage fehlschlägt. Zum Beispiel:

// We're handling a file upload here.
try {
    $rs = $db->prepare('INSERT INTO files (fileID, filename) VALUES (?, ?)');
    $rs->execute(array(1234, '/var/tmp/file1234.txt'));
} catch (Exception $e) {
    unlink('/var/tmp/file1234.txt');
    throw $e;
}

Sie erhalten eine einfache Exception-Handler schreiben möchten, dass Sie von Datenbankfehler protokolliert oder darüber informiert, dass in der Produktionsumgebung auftreten und zeigt eine freundliche Fehlermeldung an die Benutzer anstelle der Ausnahme Spur. Siehe http://www.php.net/set-exception-handler Informationen über wie das zu tun.

Andere Tipps

Ein paar Einschränkungen sind hier:

    mehrere Legacy-Probleme zu berücksichtigen, wie die Datenbankprotokollierung und Datenbankkonfigurationsmanagement
  • Dieser Code wird geschrieben.
  • Ich würde empfehlen, dass Sie bei einer bestehenden Lösung zu suchen, bevor Sie Ihre eigenen zu bauen. Viele Leute sich denken, wenn sie beginnen, dass sie nicht wollen, einen bestehenden Rahmen oder Bibliothek benutzen, weil sie zu groß, zu viel Zeit erfordern, usw. zu lernen, aber nach einer dieser Menschen gewesen I kann nicht nachdrücklich genug sagen, dass ich meine benutzerdefinierten Rahmen und Wrapper-Klassen auf einen Rahmen zu bewegen verlasse. Ich bin auf der Suche nach Zend zu bewegen, aber es gibt eine Reihe von ausgezeichneten Möglichkeiten zur Verfügung.

Oh, ich möchte darauf hinweisen, dass dieser Punkt zeigt, wie man könnte eine einzelne Funktion wickeln alle die Ausnahmebehandlung für Ihre Anfragen zu bearbeiten. Ich schreibe nicht catch-Blöcke fast überall sonst jetzt, da der Stack-Trace aus der Abfrage versuchen, mich an den Informationen alle gibt, die ich brauche, das Problem zu debuggen und zu beheben.

Hier ist meine aktuelle PDO-Wrapper-Klasse Implementierung:

class DB extends PDO 
{
    // Allows implementation of the singleton pattern -- ndg 5/24/2008
    private static $instance;

    // Public static variables for configuring the DB class for a particular database -- ndg 6/16/2008
    public static $error_table;
    public static $host_name;
    public static $db_name;
    public static $username;
    public static $password;
    public static $driver_options;
    public static $db_config_path;



    function __construct($dsn="", $username="", $password="", $driver_options=array()) 
    {
        if(isset(self::$db_config_path))
        {
            try 
            {
                if(!require_once self::$db_config_path)
                {
                    throw new error('Failed to require file: ' . self::$db_config_path); 
                }
            } 
            catch(error $e) 
            {
                $e->emailAdmin();
            }
        }
        elseif(isset($_ENV['DB']))
        {
            self::$db_config_path = 'config.db.php';

            try 
            {
                if(!require_once self::$db_config_path)
                {
                    throw new error('Failed to require file: ' . self::$db_config_path); 
                }
            } 
            catch(error $e) 
            {
                $e->emailAdmin();
            }
        }

        parent::__construct("mysql:host=" . self::$host_name . ";dbname=" .self::$db_name, self::$username, self::$password, self::$driver_options);
        $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('QueryStatement', array($this)));

        if(!isset(self::$error_table))
        {
            self::$error_table = 'errorlog_rtab';
        }
    }

    /**
     * Return a DB Connection Object
     *
     * @return DB
     */
    public static function connect()
    {

        // New PDO Connection to be used in NEW development and MAINTENANCE development
        try 
        {
            if(!isset(self::$instance))
            {   
                if(!self::$instance =  new DB())
                {
                    throw new error('PDO DB Connection failed with error: ' . self::errorInfo());
                }
            }

            return self::$instance;
        }
        catch(error $e)
        {
            $e->printErrMsg();
        }
    }

    /**
     * Returns a QueryBuilder object which can be used to build dynamic queries
     *
     * @return QueryBuilder
     * 
     */
    public function createQuery()
    {
        return new QueryBuilder();
    }

    public function executeStatement($statement, $params = null, $FETCH_MODE = null)
    {
        if($FETCH_MODE == 'scalar')
        {
            return $this->executeScalar($statement, $params);   
        }


        try {
            try {
                if(!empty($params))
                {
                    $stmt = $this->prepare($statement);
                    $stmt->execute($params);
                }
                else 
                {
                    $stmt = $this->query($statement);
                }
            }
            catch(PDOException $pdo_error)
            {
                throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
            }
        }
        catch(error $e)
        {
            $this->logDBError($e);
            $e->emailAdmin();
            return false;
        }

        try 
        {
            if($FETCH_MODE == 'all')
            {
                $tmp =  $stmt->fetchAll();
            }
            elseif($FETCH_MODE == 'column')
            {
                $arr = $stmt->fetchAll();

                foreach($arr as $key => $val)
                {
                    foreach($val as $var => $value)
                    {
                        $tmp[] = $value;
                    }
                }           
            }
            elseif($FETCH_MODE == 'row') 
            {
                $tmp =  $stmt->fetch();
            }
            elseif(empty($FETCH_MODE))
            {
                return true;
            }
        }
        catch(PDOException $pdoError)
        {
            return true;
        }

        $stmt->closeCursor();

        return $tmp;

    }

    public function executeScalar($statement, $params = null)
    {
        $stmt = $this->prepare($statement);

        if(!empty($this->bound_params) && empty($params))
        {
            $params = $this->bound_params;
        }

        try {
            try {
                if(!empty($params))
                {
                    $stmt->execute($params);
                }
                else 
                {
                        $stmt = $this->query($statement);
                }
            }
            catch(PDOException $pdo_error)
            {
                throw new error("Failed to execute query:\n" . $statement . "\nUsing Parameters:\n" . print_r($params, true) . "\nWith Error:\n" . $pdo_error->getMessage());
            }
        }
        catch(error $e)
        {
            $this->logDBError($e);
            $e->emailAdmin();
        }

        $count = $stmt->fetchColumn();

        $stmt->closeCursor();

        //echo $count;
        return $count;      
    }

    protected function logDBError($e)
    {
        $error = $e->getErrorReport();

        $sql = "
        INSERT INTO " . self::$error_table . " (message, time_date) 
        VALUES (:error, NOW())";

        $this->executeStatement($sql, array(':error' => $error));
    }
}

class QueryStatement extends PDOStatement 
{
    public $conn;

    protected function __construct() 
    {
        $this->conn = DB::connect();
        $this->setFetchMode(PDO::FETCH_ASSOC);
    }

    public function execute($bound_params = null)
    {
        return parent::execute($bound_params);          
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top