2008-11-07 14 views
30

मैं अपने भविष्य के वेबपैप में पीडीओ का उपयोग करने की सोच रहा हूं। वर्तमान में (का उपयोग करते हुए मैं क्या अतः अब तक से सीखा है), क्या मैं अपनी साइट डेटाबेस कनेक्शन को संभालने के लिए में है इस तरह एक सिंगलटन वर्ग है: के साथ सामग्री विशेषपीडीओ फ़ंक्शन में उपयोग करने का प्रयास

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

और एक अन्य फ़ाइल (functions.php) कार्यों वास्तव में इस एक की तरह लग रही:

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

अर्थ मैं कार्यों के सभी में try .. catch हिस्सा दोहराने के लिए किया है।

मेरे प्रश्न हैं:

  1. मैं कैसे और अधिक कुशल है कि करना चाहिए? (उदाहरण के लिए, सभी कार्यों में try..catch दोहराना नहीं है, और फिर भी प्रत्येक पर अलग-अलग "असफल-संदेश" वापस करने में सक्षम है)
  2. क्या यह पहले से ही एक अच्छा अभ्यास है? मैं अभी भी पीडीओ और ओओपी (अभी भी सीखने के लिए बहुत कुछ) में नया हूं, इसलिए (अभी तक), मुझे वास्तव में कोई नुकसान या चीजें नहीं दिखाई दे सकती हैं जिन्हें वहां सुधार किया जा सकता है।

मुझे खेद है कि यह अस्पष्ट या बहुत लंबा लगता है। अग्रिम में धन्यवाद।

उत्तर

38

आपका क्रियान्वयन ठीक है, और यह सबसे प्रयोजनों के लिए अच्छी तरह से पूरी तरह से काम करेंगे:

यहाँ मेरे वर्तमान पीडीओ आवरण वर्ग कार्यान्वयन है।

प्रत्येक क्वेरी को एक कोशिश/पकड़ ब्लॉक के अंदर रखना जरूरी नहीं है, और वास्तव में ज्यादातर मामलों में आप वास्तव में नहीं चाहते हैं। इसका कारण यह है कि यदि कोई प्रश्न अपवाद उत्पन्न करता है, तो यह एक वाक्यविन्यास त्रुटि या डेटाबेस समस्या जैसी घातक समस्या का परिणाम है, और ये समस्याएं नहीं हैं जिनके लिए आपको प्रत्येक क्वेरी के साथ लेखांकन करना चाहिए।

उदाहरण के लिए:

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

क्वेरी यहां या तो ठीक से काम करेंगे या बिल्कुल काम नहीं।परिस्थितियों में जहां यह काम नहीं करेगा, कभी भी उत्पादन प्रणाली पर किसी भी नियमितता के साथ नहीं होना चाहिए, इसलिए वे ऐसी स्थितियां नहीं हैं जिन्हें आपको यहां जांचना चाहिए। ऐसा करना वास्तव में प्रतिकूल है, क्योंकि आपके उपयोगकर्ताओं को एक त्रुटि मिलती है जो कभी नहीं बदलेगी, और आपको एक अपवाद संदेश नहीं मिलता है जो आपको समस्या के बारे में सूचित करेगा।

इसके बजाय, सिर्फ इस बारे में:

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

सामान्य में, केवल समय है कि आप को पकड़ने और एक प्रश्न अपवाद को संभालने के लिए चाहता हूँ है जब आप यदि क्वेरी में विफल रहता है कुछ और करना चाहते हैं। उदाहरण के लिए:

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

आप एक सरल अपवाद संचालक कि लॉग या डेटाबेस त्रुटियों कि आपके उत्पादन वातावरण में पाए जाते हैं की सूचना देता है और बजाय अपने उपयोगकर्ताओं अपवाद का पता लगाने के लिए एक दोस्ताना त्रुटि संदेश प्रदर्शित करता है लिखने के लिए चाहता हूँ। इसे कैसे करें इसके बारे में जानकारी के लिए http://www.php.net/set-exception-handler देखें।

+0

पीडी कहता है कि दूसरे के लिए, कस्टम त्रुटि वर्ग का मेरा उपयोग बस डीबी में त्रुटि लॉग करता है और मुझे एक ईमेल भेजता है। अंतिम उपयोगकर्ता कभी स्टैक ट्रेस या अन्य अप्रासंगिकता को नहीं देखता है। यही कारण है कि अगर कोई त्रुटि है तो मैं झूठी वापसी करता हूं और फिर उपयोगकर्ता को –

+0

बताता हूं कि यह निर्धारित करने के लिए मेरी क्वेरी के वापसी मूल्य का परीक्षण करें यदि आप SELECT बदलते हैं और/या किसी अन्य क्वेरी ने डेटाबेस बदल दिया है तो SELECT अब और काम नहीं करता है: आप कभी नहीं इसके बारे में तब तक पता चले जब तक कि आप अपने पृष्ठ का परीक्षण न करें। यह प्रतिकूल है। प्रत्येक क्वेरी के लिए प्रयास/पकड़ आवश्यक है! – mgutt

3

यहाँ चेतावनियां के एक जोड़े हैं:

  • इस कोड को इस तरह के डेटाबेस प्रवेश और डेटाबेस विन्यास प्रबंधन के रूप में खाते में कई विरासत मुद्दों लेने के लिए लिखा है।
  • मैं दृढ़ता से अनुशंसा करता हूं कि आप स्वयं को बनाने से पहले मौजूदा समाधान देखें। बहुत से लोग खुद को सोचते हैं कि जब वे शुरू करते हैं कि वे मौजूदा ढांचे या पुस्तकालय का उपयोग नहीं करना चाहते हैं क्योंकि वे बहुत बड़े हैं, सीखने के लिए बहुत अधिक समय की आवश्यकता है, लेकिन इन लोगों में से एक होने के बाद, जोरदार ढंग से पर्याप्त नहीं बता सकता कि मैं अपने कस्टम ढांचे और रैपर वर्गों को ढांचे में जाने के लिए छोड़ रहा हूं। मैं ज़ेंड में जाने के लिए देख रहा हूं लेकिन कई उत्कृष्ट विकल्प उपलब्ध हैं।

ओह, मुझे यह इंगित करना चाहिए कि यह बिंदु बताता है कि कोई भी आपके प्रश्नों के लिए अपवाद प्रबंधन को संभालने के लिए एक ही फ़ंक्शन को कैसे लपेट सकता है। मैं अब कहीं और कहीं भी पकड़ने की कोशिश नहीं करता क्योंकि क्वेरी से स्टैक ट्रेस मुझे वह सारी जानकारी देता है जो मुझे समस्या को डीबग करने और इसे ठीक करने की आवश्यकता है।

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);   
    } 
} 
+0

धन्यवाद, मैं कल और अधिक देखता हूं। – andyk

संबंधित मुद्दे