PHP自定义DB类中数据库连接关闭位置的技术求助
解决PHP DB类的数据库连接关闭问题
首先,咱们先理清几个关键点,帮你搞定连接关闭的问题:
为什么你的尝试没生效?
- 在方法返回前关闭连接:如果这么做,当你在同一个DB实例上调用多个方法时(比如先
selectData再updateData),第一个方法关闭连接后,后续方法就会因为连接已关闭而失败,完全不符合复用实例的需求。 - __destruct方法没生效:很大概率是因为你之前的析构函数实现有问题,或者mysqli默认不抛出异常的特性,导致连接初始化逻辑有遗漏,进而影响了析构函数的正常执行。
另外,你的代码里还有个隐藏坑:mysqli构造函数默认不会抛出异常,所以你__construct里的try/catch其实根本捕获不到连接失败的错误,这会导致后续逻辑出现不可预期的问题。
正确的解决方案
我们需要做两件核心事情:
- 开启mysqli的异常模式,确保连接错误能被正确捕获
- 实现正确的
__destruct方法,让PHP在对象被销毁时自动关闭连接
下面是修改后的完整DB类,我标注了关键修改点:
class DB { private $connection; private $username; private $password; private $db_name; private $server; private $table; function __construct($server,$username,$password,$db_name,$table) { $this->server = $server; $this->db_name = $db_name; $this->username = $username; $this->password = $password; $this->table = $table; // 关键修改1:开启mysqli异常模式,这样连接失败才会抛出异常 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); try { $this->connection = new mysqli($server,$username,$password,$db_name); // 额外添加:设置字符集,避免中文乱码问题 $this->connection->set_charset('utf8mb4'); } catch (Exception $e) { // 这里可以抛出自定义异常或者返回错误信息,根据你的业务需求调整 throw new Exception('数据库连接失败:' . $e->getMessage()); } } // 关键修改2:实现正确的析构函数,自动关闭连接 function __destruct() { // 先判断连接是否存在,避免重复关闭或调用未初始化的连接 if (isset($this->connection) && $this->connection instanceof mysqli) { $this->connection->close(); } } // 以下是你原有的方法,保持不变(如果需要优化可以后续调整) private function delArray($mainArray,$delArray) { foreach ($mainArray as $mainIndex => $mainKey) { foreach ($delArray as $delIndex => $delKey) { if ($mainKey == $delKey) { unset($mainArray[$mainIndex]); } } } return $mainArray; } public function separate($data,$type) { if ($type == 1) { $condition[0] = ''; $condition[1] = ''; foreach ($data as $index => $key) { if ($key == end($data)) { $condition[0] .= $index; $condition[1] .= "'" . $key . "'"; } else { $condition[0] .= $index . ', '; $condition[1] .= "'" . $key . "', "; } } return $condition; } else if ($type == 2) { $condition = ''; foreach ($data as $index => $key) { if ($key == end($data)) { $condition .= $index . "='" . $key . "'"; } else { $condition .= $index . "='" . $key . "', "; } } return $condition; } } private function tableColumn($nullValue=[]) { try { $result = []; $viewColumns = $this->connection->query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" . $this->db_name . "' AND TABLE_NAME = '" . $this->table . "'"); while($columnName=$viewColumns->fetch_assoc()){ $result[] = $columnName['COLUMN_NAME']; } $result = $this->delArray($result,$nullValue); return $result; } catch (Exception $e) { return $e->getMessage(); } } public function selectData($condition=[],$receive=false) { try { $condition = ($condition == []) ? '' : " WHERE " . $this->separate($condition,2); $result = $this->connection->query("SELECT * FROM " . $this->table . $condition); if ($result->num_rows > 0) { if ($receive == true) { $rowArray = []; $i = -1; while($row=$result->fetch_assoc()) { $i += 1; foreach ($this->tableColumn() as $index => $key) { $rowArray[$i][$key] = $row[$key]; } } return $rowArray; } else { return true; } } else { return false; } } catch (Exception $e) { return $e->getMessage(); } } public function createData($data,$condition=[]) { try { $valueArray = $this->separate($data,1); if (empty($condition)) { return $this->connection->query("INSERT INTO " . $this->table . " (" . $valueArray[0] . ") VALUES (" . $valueArray[1] . ")"); } else { if ($this->selectData($condition) == false) { return $this->connection->query("INSERT INTO " . $this->table . " (" . $valueArray[0] . ") VALUES (" . $valueArray[1] . ")"); } else { return false; } } } catch (Exception $e) { return $e->getMessage(); } } public function updateData($data,$condition) { try { if ($this->selectData($condition) == true) { $condition = ($condition == []) ? '' : " WHERE " . $this->separate($condition,2); $data = $this->separate($data,2); return $this->connection->query("UPDATE " . $this->table . " SET " . $data . $condition); } else { return false; } } catch (Exception $e) { return $e->getMessage(); } } public function deleteData($condition) { try { if ($this->selectData($condition) == true) { $condition = ($condition == []) ? '' : $this->separate($condition,2); return $this->connection->query("DELETE FROM " . $this->table . " WHERE " . $condition); } else { return 'does not exist'; } } catch (Exception $e) { return $e->getMessage(); } } }
补充说明
- 异常模式的重要性:开启
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)后,mysqli的所有错误都会抛出mysqli_sql_exception,这样你的try/catch才能真正捕获到连接或查询错误,避免静默失败。 - 析构函数的执行时机:当DB对象不再被引用(比如脚本执行完毕、变量被unset、变量超出作用域)时,PHP会自动调用
__destruct方法,此时关闭连接是最安全的,不会影响同一实例的其他方法调用。 - 安全提醒:你的
separate方法存在SQL注入风险,因为直接把用户输入拼接到SQL语句里了。建议改用预处理语句来绑定参数,这是生产环境必须注意的安全点。
内容的提问来源于stack exchange,提问作者Ali Yaghoubi
相关产品推荐
相关产品推荐

