PDO 断开连接和 PHP 变量引用
PDO disconnect and PHP variable reference
我是 PHP 高级别的新手。但对编程并不陌生。
我们有一个软件(已停用但仍处于活动状态)正在杀死我们的数据库。
里面用的是PDO 花了很多时间后的问题是PDO断开模式和PDO里面的use of pdo class.
public function connect() {
if(!$this->connected){
$col = 'mysql:host='
.$this->parametri->getHOST()
.';'
.'dbname='
.$this->parametri->getDB()
.';'
.'charset=utf8';
try {
// connessione tramite creazione di un oggetto PDO
$db = new PDO($col , $this->parametri->getDBUSER(),
$this->parametri->getPASS());
$this->pdoconn=$db;
$this->connected=TRUE;
}
catch(PDOException $e) {
$this->connected=FALSE;
return NULL;
}
}
return $this->pdoconn;
}
public function getPDO(){
if ($this->connected){
return $this->pdoconn;
}else {
return NULL;
}
}
public function disconnect() {
$this->pdoconn=null;
$this->connected=FALSE;
}
在官方网站上阅读 PDO 文档和评论当 $this->pdoconn=null 时连接被释放;
但它已通过 getPDO() 传递。
根据 this article and this dissertion,某处可能有一个指向连接的变量,因此连接永远不会被释放; class 认为连接已释放,当请求创建新连接时,最后一个连接丢失给 class 的用户。
所以我的想法是将连接 tu null 也传回这个或者有另一种方法来保护 pdoconn 并强制为 null。
public function disconnect(&$var) {
$var=null;
$this->pdoconn=null;
$this->connected=FALSE;
}
另一种方法是构建另一个永远不会暴露 pdo conn 的包装 class 并强制在其中执行查询以管理断开连接。
也许尝试将连接 and/or class 设为 singleton
,然后它应该保持数据库连接,并且每次您使用它时,它都将是同一个连接。这样一来,就不用每次使用都集中精力关闭连接了,因为整个页面只有一个连接。这是一个简单的例子:
class MyClass
{
// You can make the class itself persist to save on resources
private static $obj;
// You can save the connection specifically to reuse it
private static $singleton;
// Return itself to static var
public function __construct()
{
if(!empty(self::$obj)) {
echo 'OLD OBJ<br />';
return self::$obj;
}
echo 'NEW OBJ<br />';
self::$obj = $this;
return self::$obj;
}
// Return connection if already set
public function connect($username = "username",$password = "password",$host = "host",$database = "dbname")
{
if(!empty(self::$singleton)) {
echo 'OLD CONN<br />';
return self::$singleton;
}
try {
self::$singleton = new PDO('mysql:host='.$host.';dbname='.$database.';charset=utf8',$username,$password);
}
catch(PDOException $e) {
die('connection failed');
}
echo 'NEW CONN<br />';
return self::$singleton;
}
}
使用示例:
// Creates first PDO connection
$database = new MyClass();
$con1 = $database->connect();
function getConnection()
{
// Creates first connection
$database = new MyClass();
return $database->connect();
}
// Won't create a new instance, but rather use the same.
$con2 = getConnection();
会写:
NEW OBJ
NEW CONN
OLD OBJ
OLD CONN
这就是我实现单例数据库实例以保持持久数据库连接的方式:
class DB implements IConnectInfo {
public static function factory() {
if( self::$_instance === null ) {
self::$_instance = new DB( 'HOST', 'USERNAME', 'PASSWORD', 'DATABASE' );
}
return self::$_instance;
}
protected function __construct( $host, $username, $password, $database ) {
try {
$this->_link = new PDO( "mysql:host={$host};dbname={$database}", $username, $password, array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) );
$this->_link->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$this->_link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
$this->_link = null;
die( "ERROR: Could not connect to the database" );
}
}
public function __destruct() {
if ( $this->_hasActiveTransaction ) {
$this->commit();
}
}
final private function __clone() {
}
public function &link() {
return $this->_link;
}
public function beginTransaction() {
if ( $this->_hasActiveTransaction == false ) {
try {
$this->_link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_link->beginTransaction();
$this->_hasActiveTransaction = true;
return true;
} catch (PDOException $e) {
error_log($e);
die();
return false;
}
}
return true;
}
public function rollBack() {
if( !$this->beginTransaction() ) {
return false;
}
try {
$this->_link->rollBack();
$this->_hasActiveTransaction = false;
return true;
} catch (PDOException $e) {
error_log($e);
return false;
}
}
public function commit() {
if( !$this->beginTransaction() ) {
return false;
}
try {
$this->_link->commit();
$this->_hasActiveTransaction = false;
return true;
} catch (PDOException $e) {
$this->rollBack();
return false;
}
}
private $_hasActiveTransaction = false;
private $_result = null;
private $_link = null;
static private $_instance = null;
}
然后我像这样使用它:
$DB = DB::factory();
$query = "SELECT * FROM myTable";
$stmt = $DB->link()->prepare( $query );
$stmt->execute();
while( $myTableObj = $stmt->fetch( PDO::FETCH_OBJ ) ) {
echo $myTableObj->myField
}
我是 PHP 高级别的新手。但对编程并不陌生。
我们有一个软件(已停用但仍处于活动状态)正在杀死我们的数据库。
里面用的是PDO 花了很多时间后的问题是PDO断开模式和PDO里面的use of pdo class.
public function connect() {
if(!$this->connected){
$col = 'mysql:host='
.$this->parametri->getHOST()
.';'
.'dbname='
.$this->parametri->getDB()
.';'
.'charset=utf8';
try {
// connessione tramite creazione di un oggetto PDO
$db = new PDO($col , $this->parametri->getDBUSER(),
$this->parametri->getPASS());
$this->pdoconn=$db;
$this->connected=TRUE;
}
catch(PDOException $e) {
$this->connected=FALSE;
return NULL;
}
}
return $this->pdoconn;
}
public function getPDO(){
if ($this->connected){
return $this->pdoconn;
}else {
return NULL;
}
}
public function disconnect() {
$this->pdoconn=null;
$this->connected=FALSE;
}
在官方网站上阅读 PDO 文档和评论当 $this->pdoconn=null 时连接被释放; 但它已通过 getPDO() 传递。
根据 this article and this dissertion,某处可能有一个指向连接的变量,因此连接永远不会被释放; class 认为连接已释放,当请求创建新连接时,最后一个连接丢失给 class 的用户。
所以我的想法是将连接 tu null 也传回这个或者有另一种方法来保护 pdoconn 并强制为 null。
public function disconnect(&$var) {
$var=null;
$this->pdoconn=null;
$this->connected=FALSE;
}
另一种方法是构建另一个永远不会暴露 pdo conn 的包装 class 并强制在其中执行查询以管理断开连接。
也许尝试将连接 and/or class 设为 singleton
,然后它应该保持数据库连接,并且每次您使用它时,它都将是同一个连接。这样一来,就不用每次使用都集中精力关闭连接了,因为整个页面只有一个连接。这是一个简单的例子:
class MyClass
{
// You can make the class itself persist to save on resources
private static $obj;
// You can save the connection specifically to reuse it
private static $singleton;
// Return itself to static var
public function __construct()
{
if(!empty(self::$obj)) {
echo 'OLD OBJ<br />';
return self::$obj;
}
echo 'NEW OBJ<br />';
self::$obj = $this;
return self::$obj;
}
// Return connection if already set
public function connect($username = "username",$password = "password",$host = "host",$database = "dbname")
{
if(!empty(self::$singleton)) {
echo 'OLD CONN<br />';
return self::$singleton;
}
try {
self::$singleton = new PDO('mysql:host='.$host.';dbname='.$database.';charset=utf8',$username,$password);
}
catch(PDOException $e) {
die('connection failed');
}
echo 'NEW CONN<br />';
return self::$singleton;
}
}
使用示例:
// Creates first PDO connection
$database = new MyClass();
$con1 = $database->connect();
function getConnection()
{
// Creates first connection
$database = new MyClass();
return $database->connect();
}
// Won't create a new instance, but rather use the same.
$con2 = getConnection();
会写:
NEW OBJ
NEW CONN
OLD OBJ
OLD CONN
这就是我实现单例数据库实例以保持持久数据库连接的方式:
class DB implements IConnectInfo {
public static function factory() {
if( self::$_instance === null ) {
self::$_instance = new DB( 'HOST', 'USERNAME', 'PASSWORD', 'DATABASE' );
}
return self::$_instance;
}
protected function __construct( $host, $username, $password, $database ) {
try {
$this->_link = new PDO( "mysql:host={$host};dbname={$database}", $username, $password, array( PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8" ) );
$this->_link->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$this->_link->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
$this->_link = null;
die( "ERROR: Could not connect to the database" );
}
}
public function __destruct() {
if ( $this->_hasActiveTransaction ) {
$this->commit();
}
}
final private function __clone() {
}
public function &link() {
return $this->_link;
}
public function beginTransaction() {
if ( $this->_hasActiveTransaction == false ) {
try {
$this->_link->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->_link->beginTransaction();
$this->_hasActiveTransaction = true;
return true;
} catch (PDOException $e) {
error_log($e);
die();
return false;
}
}
return true;
}
public function rollBack() {
if( !$this->beginTransaction() ) {
return false;
}
try {
$this->_link->rollBack();
$this->_hasActiveTransaction = false;
return true;
} catch (PDOException $e) {
error_log($e);
return false;
}
}
public function commit() {
if( !$this->beginTransaction() ) {
return false;
}
try {
$this->_link->commit();
$this->_hasActiveTransaction = false;
return true;
} catch (PDOException $e) {
$this->rollBack();
return false;
}
}
private $_hasActiveTransaction = false;
private $_result = null;
private $_link = null;
static private $_instance = null;
}
然后我像这样使用它:
$DB = DB::factory();
$query = "SELECT * FROM myTable";
$stmt = $DB->link()->prepare( $query );
$stmt->execute();
while( $myTableObj = $stmt->fetch( PDO::FETCH_OBJ ) ) {
echo $myTableObj->myField
}