Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 函数中的PDO try catch用法_Php_Pdo - Fatal编程技术网

Php 函数中的PDO try catch用法

Php 函数中的PDO try catch用法,php,pdo,Php,Pdo,我正在考虑在我未来的所有网络应用程序中使用PDO。目前(使用到目前为止我从中学到的知识),我在我的站点中处理数据库连接的是这样一个单例类: class DB { private static $instance = NULL; private static $dsn = "mysql:host=localhost;dbname=mydatabase;"; private static $db_user = 'root'; private static

我正在考虑在我未来的所有网络应用程序中使用PDO。目前(使用到目前为止我从中学到的知识),我在我的站点中处理数据库连接的是这样一个单例类:

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
部分

我的问题是:

  • 我应该如何提高效率?(例如,不必在所有函数中重复
    try..catch
    ,但仍然能够在每个函数上返回不同的“失败消息”)
  • 这已经是一个好的做法了吗?我还是PDO和OOP的新手(还有很多东西需要学习),所以(到目前为止),我真的看不出有什么缺点或可以改进的地方

  • 如果这看起来不清楚或太长,我很抱歉。提前感谢。

    这里有几个注意事项:

    • 编写此代码是为了考虑一些遗留问题,例如数据库日志记录和数据库配置管理
    • 我强烈建议您在构建自己的解决方案之前先查看现有的解决方案。很多人一开始会想,他们不想使用现有的框架或库,因为它们太大,需要太多的时间来学习,等等,但是在成为这些人中的一员之后,我无法强调我将离开我的自定义框架和包装类,转而使用框架。我想搬到Zend,但是有很多很好的选择
    哦,我应该指出,这一点说明了如何包装一个函数来处理查询的所有异常处理。我现在几乎不在其他任何地方编写try-catch块,因为查询中的堆栈跟踪提供了调试问题和修复问题所需的所有信息

    以下是我当前的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($_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);          
        }
    }
    

    您的实现很好,在大多数情况下都能很好地工作

    没有必要将每个查询都放在try/catch块中,事实上,在大多数情况下,您实际上不想这样做。原因是,如果查询生成异常,它是致命问题(如语法错误或数据库问题)的结果,而这些问题不应在您执行的每个查询中进行说明

    例如:

    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!");
    }
    
    // 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;
    }
    
    这里的查询要么正常工作,要么根本不工作。它根本不起作用的情况不应该在生产系统中有任何规律地发生,因此它们不是您应该在这里检查的条件。这样做实际上会适得其反,因为您的用户会收到一个永远不会更改的错误,并且您不会收到一条异常消息来提醒您这个问题

    相反,只需写下以下内容:

    $rs = $db->prepare('SELECT * FROM foo');
    $rs->execute();
    $foo = $rs->fetchAll();
    
    通常,您希望捕获和处理查询异常的唯一时间是,如果查询失败,您希望执行其他操作。例如:

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

    您需要编写一个简单的异常处理程序,记录或通知生产环境中发生的数据库错误,并向用户显示友好的错误消息,而不是异常跟踪。有关如何执行此操作的信息,请参阅。

    要了解pd所说的内容,我使用自定义错误类只是将错误记录到db并向我发送电子邮件。最终用户从未看到堆栈跟踪或其他不友好的情况。这就是为什么如果出现错误,我会返回false,然后测试查询的返回值,以确定如果您更改了SELECT和/或其他查询更改了数据库,使SELECT不再起作用,那么应该告诉用户什么:在您自己测试页面之前,您永远不会知道这一点。这会适得其反。每个查询都需要try/catch!