1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
classDB {
public$conn;
publicfunction__construct() {
$this->cOnn= mysql_connect('localhost','root','');
mysql_select_db('test',$this->conn);
}
publicfunctionquery($sql) {
returnmysql_query($sql,$this->conn);
}
publicfunction__destruct() {
echo"destruct:close
";
mysql_close($this->conn);
}
}
|
执行:
1
2
3
4
|
//class DB ..
$db=newDB;
?>
|
正常打印destruct:close。
再来看看下面的会话重定向到DB:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
classDB {
public$conn;
publicfunction__construct() {
$this->cOnn= mysql_connect('localhost','root','');
mysql_select_db('test',$this->conn);
}
publicfunctionquery($sql) {
returnmysql_query($sql,$this->conn);
}
publicfunction__destruct() {
echo"destruct:close
";
mysql_close($this->conn);
}
}
classSessionHandler {
publicstatic$db;
functionopen() {
}
functionclose() {
}
functionread() {
}
functionwrite($id,$data) {
echo"session:write
";
$sql="REPLACE INTO session VALUES('$id', '$data')";
self::$db->query($sql);
}
functiondestroy() {
}
functiongc() {
}
}
SessionHandler::$db=newDB;
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'] ='深空';
?>
|
这次析构正常,只不过会话写入出错了,析构在会话写入之前被执行了:
1
2
3
4
|
destruct:close
session:write
Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12
|
厄,见鬼了吧,PHP竟然在脚本执行结束后先执行析构函数,然后才处理会话。
我再稍微修改一下 SessionHandler:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
classDB {
public$conn;
publicfunction__construct() {
$this->cOnn= mysql_connect('localhost','root','');
mysql_select_db('test',$this->conn);
}
publicfunctionquery($sql) {
returnmysql_query($sql,$this->conn);
}
publicfunction__destruct() {
echo"destruct:close
";
mysql_close($this->conn);
}
}
classSessionHandler {
functionopen() {
}
functionclose() {
}
functionread() {
}
functionwrite($id,$data) {
global$db;
echo"session:write
";
$sql="REPLACE INTO session VALUES('$id', '$data')";
$db->query($sql);
}
functiondestroy() {
}
functiongc() {
}
}
$db=newDB();
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'] ='深空';
?>
|
输出如下:
1
2
3
4
|
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执行的时候,这些变量还没有被销毁,我又做了如下修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
classDB {
public$conn;
publicfunction__construct() {
$this->cOnn= mysql_connect('localhost','root','');
mysql_select_db('test',$this->conn);
}
publicfunctionquery($sql) {
returnmysql_query($sql,$this->conn);
}
publicfunction__destruct() {
echo"destruct:close
";
mysql_close($this->conn);
}
}
classSessionHandler {
functionopen() {
}
functionclose() {
}
functionread() {
}
functionwrite($id,$data) {
global$db;
echo"session:write
";
$sql="REPLACE INTO session VALUES('$id', '$data')";
$db['session']->query($sql);
}
functiondestroy() {
}
functiongc() {
}
}
$db['session'] =newDB();
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'] ='深空';
?>
|
输出:
1
2
3
4
|
destruct:close
session:write
Warning: mysql_query(): 2 is not a valid MySQL-Link resource on line 12
|
呵呵,这次$db没有被销毁,因为它是个数组变量,后来和同事分析觉得可能是这些变量和对象的存储方式不一样,销毁的顺序也不一样导致的。不过__destruct仍然是在write前执行,基本上可以判断会话是在很后面才执行的。要解决这个问题,只能去掉DB的__destruct方法。
我没有去深究PHP内部对变量的处理和回收方式,只是在重定向会话处理方法的时候这个问题才显露出来,是个比较有趣的问题,发出来和大家分享我的发现主要是想让大家在碰到这个问题的时候不会太浪费时间在调试上。
希望明真相的高手不吝指点。