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->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 连接和抽象类的主要内容,如果未能解决你的问题,请参考以下文章