【问题标题】:PDO Connection and abstract classPDO 连接和抽象类
【发布时间】:2016-01-09 02:39:59
【问题描述】:

我正在使用带有 PDO 的抽象类。我想知道是否有必要每次都将 $conn 变量设为空,或者在脚本结束时它是否自己这样做?

您能否告诉我,对于这种类型的结构,取消$conn 的最佳方法是什么?

abstract class DB_Connection
{
    protected static $tbl_admin = "prof_admin";
    //protected static $tbl_admin = "prof_admin";

    protected static function obj_db()
    {
        $servername = "localhost";
        $username = "root";
        $password = "";
        $dbname = "salmanshahid";
        $conn = null;

        try 
        {
            $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
            // set the PDO error mode to exception
            $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $conn;
        }
        catch(PDOException $e)
        {
            echo $sql . "<br>" . $e->getMessage();
        } 
    }
    protected static function select($query)
    {
        try 
        {
            $conn = self::obj_db();
            $stmt = $conn->prepare($query);
            $stmt->execute();

            // set the resulting array to associative
            $stmt->setFetchMode(PDO::FETCH_ASSOC); 
            return $stmt->fetchAll();
        }
        catch(PDOException $e) 
        {
            throw new Exception("Error In SELECT STATMENT: " . $e->getMessage());
        }
    }
    protected static function insert($query)
    {
        try 
        {
            $conn = self::obj_db();
            $stmt = $conn->prepare($query);
            $stmt->execute();
        }
        catch(PDOException $e) 
        {
            throw new Exception("Error In INSERT STATMENT: " . $e->getMessage());
        }
    }

}

【问题讨论】:

    标签: php oop pdo


    【解决方案1】:

    或者如果脚本结束时它自己这样做?

    是的,当然,PHP 会自动关闭并清理脚本执行过程中打开的所有资源,所以不用担心手动关闭它。

    无论如何,要使 conn 无效,只需将其无效:$this-&gt;conn = NULL;

    但是与你班级的其他问题相比,所有这些东西完全可以忽略不计,这些问题不安全、低效且无法使用。

    • 首先,我不知道你为什么要让这个类抽象。抽象类是 prototype 类,曾经是其他类的来源。但是数据库包装器是一个准备好使用的最终类。我认为没有必要将其抽象化。
    • 错误报告也是多余的和不一致的。在错误消息中添加“Error In SELECT STATMENT”是毫无用处的。虽然连接错误处理显然是错误的。相反,让 PDO 抛出一个异常,然后让它过去。它的处理方式与您网站中的任何其他错误相同。
    • 下一个问题是安全性。由于某种原因,select()insert() 函数都不支持 prepared statements,这使得它们变得非常无用:您可以使用 PDO::query() 代替,结果完全相同。但是你真正需要的是正确使用准备/执行,通过在查询中使用占位符,同时将实际变量发送到execute()
    • 另一个问题是重复代码:两个函数几乎相同。
    • 同时这两个函数都非常不可靠:select() 函数仅限于一种类型的结果集,而insert() 根本不返回任何内容。相反,您可以只使用单个函数来运行所有查询,并使其返回语句,这将非常有用。它可以让您获得 PDO 支持的几十种不同格式的返回数据,甚至可以让您从 DML 查询中获得受影响的行数

    让我建议你另一种方法,一个简单的 PDO 包装器,可以让你以最简单和安全的方式使用 PDO:

    <?php
    define('DB_HOST', 'localhost');
    define('DB_NAME', 'test');
    define('DB_USER', 'root');
    define('DB_PASS', '');
    define('DB_CHAR', 'utf8');
    
    class DB
    {
        protected static $instance = null;
    
        public function __construct() {}
        public function __clone() {}
    
        public static function instance()
        {
            if (self::$instance === null)
            {
                $opt  = array(
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    PDO::ATTR_EMULATE_PREPARES   => TRUE,
                );
                $dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset='.DB_CHAR;
                self::$instance = new PDO($dsn, DB_USER, DB_PASS, $opt);
            }
            return self::$instance;
        }
    
        public static function __callStatic($method, $args)
        {
            return call_user_func_array(array(self::instance(), $method), $args);
        }
    
        public static function run($sql, $args = [])
        {
            $stmt = self::instance()->prepare($sql);
            $stmt->execute($args);
            return $stmt;
        }
    }
    

    它非常强大、安全且易于使用。

    您可以使用任何 PDO 函数,只需在 DB:: 前缀之后添加它的调用:

    $stmt = DB::query("SELECT * FROM table WHERE foo='bar'");
    

    所以,首先,它是一个PDO 包装器,它能够通过使用魔术__call() 方法来运行任何PDO 方法。我添加的唯一函数是run()

    我建议您使用一种通用的run() 方法,而不是您自己的不安全和不可靠的select()insert() 方法,这只不过是这三行的简写:

    $stmt = DB::prepare($query);
    $stmt->execute($params);
    $data = $stmt->fetch();
    

    所以,你可以把它写成一个简洁的单行:

    $data = DB::run($query, $params)->fetch();
    

    请注意,它可以运行任何类型的查询并以 PDO 支持的任何格式返回结果。

    我写了一篇关于这个简单包装器的文章,您可以在其中找到一些使用示例。所有示例代码都可以按原样运行,只需将其复制并粘贴到您的脚本中并设置凭据:http://phpdelusions.net/pdo/pdo_wrapper#samples

    【讨论】:

    • 1.为什么不使用抽象类? 2. 如果您不允许直接访问公共静态函数 run($sql, $args = []);那么为什么不将其用作受保护的或私有的,为什么要公开呢? 3. __callStatic($method, $args);会被调用来调用 run() 和这个类的其他本地函数吗? 4. 并且告诉我这是在公共静态函数 __destruct() 中取消 $conn 的好方法; 5. 告诉我如何使用你的类使用异常处理。
    • 谢谢!了解你的观点。现在我需要使用完全相同的 PDO 类来构建用户类,并且我已经编码了用户类,并且肯定需要你的 cmets 但无法在这里发布我应该在哪里发布请建议。
    • 你对抽象类的理解很好。事实上,我也想过使用抽象的实现数据库包装器。你能解释一下什么时候使用抽象类吗?
    猜你喜欢
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    • 2011-01-06
    相关资源
    最近更新 更多