Domanda

Sto pensando di usare DOP in tutte le mie webapp future. Attualmente (usando quello che ho imparato finora), quello che ho nel mio sito per gestire la connessione al database è una classe Singleton come questa:

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;
    }
}

e un altro file (Functions.php) con funzioni specifiche del contenuto esattamente come questo:

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";
    }
}
...

significa che devo ripetere la parte try .. catch in tutte le funzioni.

Le mie domande sono:

  1. Come dovrei renderlo più efficiente? (ad es. non dover ripetere try..catch in tutte le funzioni e tuttavia essere in grado di restituire diversi "messaggi di errore" su ciascuno di essi
  2. È già una buona pratica? Sono ancora nuovo in DOP e OOP (ancora molto da imparare), quindi (per ora), non riesco davvero a vedere alcun svantaggio o cose che possano essere migliorati lì.

Mi dispiace se sembra poco chiaro o troppo lungo. Grazie in anticipo.

È stato utile?

Soluzione

L'implementazione va bene e funzionerà perfettamente per la maggior parte degli scopi.

Non è necessario inserire ogni query all'interno di un blocco try / catch, e in effetti nella maggior parte dei casi non si desidera. Il motivo di ciò è che se una query genera un'eccezione, è il risultato di un problema fatale come un errore di sintassi o un problema di database e quelli non sono problemi che dovresti tenere in considerazione con ogni query che esegui.

Ad esempio:

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!");
}

La query qui funzionerà correttamente o non funzionerà affatto. Le circostanze in cui non funzionerebbe affatto non dovrebbero mai verificarsi con regolarità su un sistema di produzione, quindi non sono condizioni che dovresti verificare qui. Farlo è in realtà controproducente, perché i tuoi utenti ricevono un errore che non cambierà mai e non ricevi un messaggio di eccezione che ti avviserebbe del problema.

Invece, basta scrivere questo:

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

In generale, l'unica volta che vorrai catturare e gestire un'eccezione di query è quando vuoi fare qualcos'altro se la query fallisce. Ad esempio:

// 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;
}

Ti consigliamo di scrivere un semplice gestore di eccezioni che registri o ti avvisi di errori del database che si verificano nel tuo ambiente di produzione e visualizzi un messaggio di errore amichevole agli utenti invece della traccia delle eccezioni. Vedi http://www.php.net/set-exception-handler per informazioni su come farlo.

Altri suggerimenti

Un paio di avvertenze qui sono:

  • Questo codice è stato scritto per tenere conto di diversi problemi legacy come la registrazione del database e la gestione della configurazione del database.
  • Consiglio vivamente di guardare una soluzione esistente prima di crearne una tua. Molte persone pensano a se stesse quando iniziano a non voler usare un framework o una libreria esistenti perché sono troppo grandi, richiedono troppo tempo per imparare, ecc., Ma dopo essere stata una di queste persone non posso affermare con enfasi sufficiente che sto lasciando il mio framework personalizzato e le classi wrapper per passare a un framework. Sto cercando di trasferirmi a Zend ma ci sono una serie di eccellenti scelte disponibili.

Oh, dovrei sottolineare che questo punto illustra come si potrebbe racchiudere una singola funzione per gestire tutta la gestione delle eccezioni per le vostre query. Non scrivo prova a catturare blocchi quasi ovunque ora perché la traccia dello stack dalla query mi fornisce tutte le informazioni di cui ho bisogno per eseguire il debug del problema e risolverlo.

Ecco la mia attuale implementazione della classe wrapper PDO:

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(

Un paio di avvertenze qui sono:

  • Questo codice è stato scritto per tenere conto di diversi problemi legacy come la registrazione del database e la gestione della configurazione del database.
  • Consiglio vivamente di guardare una soluzione esistente prima di crearne una tua. Molte persone pensano a se stesse quando iniziano a non voler usare un framework o una libreria esistenti perché sono troppo grandi, richiedono troppo tempo per imparare, ecc., Ma dopo essere stata una di queste persone non posso affermare con enfasi sufficiente che sto lasciando il mio framework personalizzato e le classi wrapper per passare a un framework. Sto cercando di trasferirmi a Zend ma ci sono una serie di eccellenti scelte disponibili.

Oh, dovrei sottolineare che questo punto illustra come si potrebbe racchiudere una singola funzione per gestire tutta la gestione delle eccezioni per le vostre query. Non scrivo prova a catturare blocchi quasi ovunque ora perché la traccia dello stack dalla query mi fornisce tutte le informazioni di cui ho bisogno per eseguire il debug del problema e risolverlo.

Ecco la mia attuale implementazione della classe wrapper PDO:

<*>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); } }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top