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
}