DOP tenta di catturare l'utilizzo nelle funzioni

Sto pensando di usare PDO in tutta la mia futura webapp. Attualmente (usando quello che ho imparato da SO finora), quello che ho nel mio sito per gestire la connessione al database è una class 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 che assomigliano esattamente a 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"; } } ... 

nel senso che devo ripetere la try .. catch parte a tutte le funzioni.

Le mie domande sono:

  1. Come dovrei renderlo più efficiente? (ad esempio non wherer ripetere try..catch in tutte le funzioni, e tuttavia ancora in grado di restituire "messaggi di errore" diversi su ognuno di essi)
  2. È già una buona pratica? Sono ancora nuovo a PDO e OOP (ancora molto altro da imparare), quindi (a partire da ora), non riesco davvero a vedere alcun svantaggio o cose che possano essere migliorate.

Mi dispiace se questo non è chiaro o troppo lungo. Grazie in anticipo.

    La tua implementazione va bene e functionrà perfettamente per la maggior parte degli scopi.

    Non è necessario inserire tutte le query all'interno di un block try / catch, e in effetti nella maggior parte dei casi non è ansible. La ragione di ciò è che se una query genera un'exception, è il risultato di un problema irreversibile come un errore di syntax o di un problema di database e questi non sono problemi che dovresti tenere conto di each query che fai.

    Per 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 functionrà correttamente o non functionrà affatto. Le circostanze in cui non functionrebbe affatto non dovrebbero mai verificarsi con regolarità su un sistema di produzione, quindi non sono condizioni da controllare qui. Fare ciò è in realtà controproducente, perché i tuoi utenti ricevono un errore che non cambierà mai e non riceverai un messaggio di exception che ti avviserà del problema.

    Invece, scrivi questo:

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

    In generale, l'unica volta in cui si desidera rilevare e gestire un'exception di query è quando si desidera eseguire qualcos'altro se la query non riesce. Per esempio:

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

    Dovrai scrivere un semplice gestore di eccezioni che registri o ti avvisi degli errori di database che si verificano nell'ambiente di produzione e visualizza un messaggio di errore amichevole ai tuoi utenti invece della traccia di exception. Vedi http://www.php.net/set-exception-handler per informazioni su come farlo.

    Un paio di avvertenze qui sono:

    • Questo codice è stato scritto per tenere in considerazione diversi problemi preesistenti come la logging del database e la gestione della configuration del database.
    • Consiglio vivamente di consultare una soluzione esistente prima di crearne una nuova. Molte persone pensano a se stesse quando iniziano che non vogliono usare una struttura o una biblioteca esistente perché sono troppo grandi, richiedono troppo tempo per imparare, ecc., Ma dopo essere stata una di queste persone non posso affermare con enfasi che sto lasciando le mie classi personalizzate di framework e wrapper per passare a un framework. Sto cercando di passare a Zend, ma ci sono un certo numero di scelte eccellenti disponibili.

    Oh, vorrei sottolineare che questo punto illustra come si possa racchiudere una singola function per gestire tutta la gestione delle eccezioni per le query. Non scrivo try catch blocks quasi da nessun'altra parte 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 class 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=arrays()) { 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, arrays('QueryStatement', arrays($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, arrays(':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); } }