PDO 连接和抽象类

Posted

技术标签:

【中文标题】PDO 连接和抽象类【英文标题】:PDO Connection and abstract class 【发布时间】: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());
        
    


【问题讨论】:

【参考方案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 但无法在这里发布我应该在哪里发布请建议。 你对抽象类的理解很好。事实上,我也想过使用抽象的实现数据库包装器。你能解释一下什么时候使用抽象类吗?

以上是关于PDO 连接和抽象类的主要内容,如果未能解决你的问题,请参考以下文章

抽象类中的新pdo

初识PDO数据库抽象层

PDO(数据访问抽象层)pdo事务功能和预处理功能---2017-05-05

pdo

Pdo

数据库抽象层PDO 8-1