今天和同事又讨论到DB类中析构函数是否要关闭数据库连接的问题,粗略看起来貌似在DB对象销毁之前关闭数据库连接再正常不过:
[php]class DB {
public $conn;
public function __construct() {
$this->conn = mysql_connect('localhost', 'root', '');
mysql_select_db('test', $this->conn);
}
public function query($sql) {
return mysql_query($sql, $this->conn);
}
public function __destruct() {
echo "destruct:close<br />";
mysql_close($this->conn);
}
}[/php]
执行:
[php]<?php
//class DB ..
$db = new DB;
?>[/php]
正常打印 destruct:close 。
再来看看下面的会话重定向到DB:
[php]<?php
class DB {
public $conn;
public function __construct() {
$this->conn = mysql_connect('localhost', 'root', '');
mysql_select_db('test', $this->conn);
}
public function query($sql) {
return mysql_query($sql, $this->conn);
}
public function __destruct() {
echo "destruct:close<br />";
mysql_close($this->conn);
}
}
class SessionHandler {
public static $db;
function open() {
}
function close() {
}
function read() {
}
function write($id, $data) {
echo "session:write<br />";
$sql = "REPLACE INTO session VALUES('$id', '$data')";
self::$db->query($sql);
}
function destroy() {
}
function gc() {
}
}
SessionHandler::$db = new DB;
session_set_save_handler(array('SessionHandler', 'open'),
array('SessionHandler', 'close'), array('SessionHandler', 'read'),
array('SessionHandler', 'write'), array('SessionHandler', 'destroy'),
array('SessionHandler', 'gc'));
session_start();
$_SESSION['user'] = '深空';
?>[/php]
这次析构正常,只不过会话写入出错了,析构在会话写入之前被执行了:
destruct:close
session:write
Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12
厄,见鬼了吧,PHP竟然在脚本执行结束后先执行析构函数,然后才处理会话。
我再稍微修改一下 SessionHandler:
[php]<?php
class DB {
public $conn;
public function __construct() {
$this->conn = mysql_connect('localhost', 'root', '');
mysql_select_db('test', $this->conn);
}
public function query($sql) {
return mysql_query($sql, $this->conn);
}
public function __destruct() {
echo "destruct:close<br />";
mysql_close($this->conn);
}
}
class SessionHandler {
function open() {
}
function close() {
}
function read() {
}
function write($id, $data) {
global $db;
echo "session:write<br />";
$sql = "REPLACE INTO session VALUES('$id', '$data')";
$db->query($sql);
}
function destroy() {
}
function gc() {
}
}
$db = new DB();
session_set_save_handler(array('SessionHandler', 'open'),
array('SessionHandler', 'close'), array('SessionHandler', 'read'),
array('SessionHandler', 'write'), array('SessionHandler', 'destroy'),
array('SessionHandler', 'gc'));
session_start();
$_SESSION['user'] = '深空';
?>[/php]
输出如下:
destruct:close
session:write
Fatal error: Call to a member function query() on a non-object on line 35
这次报错让我感到意外,根据提示可以认定35行的$db变量不是个对象,后来想想也确实应该是这样,因为__destruct方法已经执行了,那么其
实对象在write之前已经被销毁了,所以找不到$db变量已经是空的,不足为奇。我又测试了一些字符串和数组变量,发现write执行的时候,这些变量
还没有被销毁,我又做了如下修改:
[php]<?php
class DB {
public $conn;
public function __construct() {
$this->conn = mysql_connect('localhost', 'root', '');
mysql_select_db('test', $this->conn);
}
public function query($sql) {
return mysql_query($sql, $this->conn);
}
public function __destruct() {
echo "destruct:close<br />";
mysql_close($this->conn);
}
}
class SessionHandler {
function open() {
}
function close() {
}
function read() {
}
function write($id, $data) {
global $db;
echo "session:write<br />";
$sql = "REPLACE INTO session VALUES('$id', '$data')";
$db['session']->query($sql);
}
function destroy() {
}
function gc() {
}
}
$db['session'] = new DB();
session_set_save_handler(array('SessionHandler', 'open'),
array('SessionHandler', 'close'), array('SessionHandler', 'read'),
array('SessionHandler', 'write'), array('SessionHandler', 'destroy'),
array('SessionHandler', 'gc'));
session_start();
$_SESSION['user'] = '深空';
?>[/php]
输出:
destruct:close
session:write
Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12
呵呵,这次$db没有被销毁,因为它是个数组变量,后来和同事分析觉得可能是这些变量和对象的存储方式不一样,销毁的顺序也不一样导致的。不过
__destruct仍然是在write前执行,基本上可以判断会话是在很后面才执行的。要解决这个问题,只能去掉DB的__destruct方法。
我没有去深究PHP内部对变量的处理和回收方式,只是在重定向会话处理方法的时候这个问题才显露出来,是个比较有趣的问题,发出来和大家分享我的发现主要是想让大家在碰到这个问题的时候不会太浪费时间在调试上。www.zhenaish.com
希望明真相的高手不吝指点。
转载于:https://www.cnblogs.com/zayy/p/3454153.html