MySQLi在析构函数中关闭,立即触发

时间:2017-04-07 22:42:16

标签: php mysql oop mysqli

我最近一直在重新设计一个古老的PHP应用程序,它的大部分代码都包含1000多行长的PHP文件。我首先将大部分代码重构为类。我最近一直在研究数据库连接,并开始为它编写一个类。我决定将$mysqli->close()抛入析构函数(我正在使用OO方法)。

不幸的是,我几乎立即遇到了问题。当页面完成渲染(或者没有更多对DB对象的引用)时,不是关闭MySQLi连接,而是立即关闭。我通过编写一个简单的测试来测试它:

$db = new DBConnect(); //My abstraction class
$db->getSQL()->query("SELECT 1"); //Query fails. Error message states connection closed.

我的析构函数看起来像这样:

public function __destruct() {
    $this->mysqli->close();
}

我的构造函数如下所示:

public function __construct() {
     $this->mysqli=new mysqli(\MainConfig::$database['host'], \MainConfig::$database['user'], \MainConfig::$database['pass'], \MainConfig::$database['db']);
     if($this->mysqli->connect_error) {
          die('Connect error (' . $this->mysqli->connect_errno . ') ' . $this->mysqli->connect_error); //This is not ever fired.
     }
}

我知道这不是关闭连接的其他一些代码,因为如果我注释掉$this->mysqli->close()行,那么代码按预期工作。在我看来,析构函数立即激发 ,这不是理想的行为。我误解了他们打算如何工作吗?

1 个答案:

答案 0 :(得分:2)

我能够使用代码重现您描述的行为:

<?php

class DestructorTest {
    public function getter() {
        print "DestructorTest::getter() called\n";
        return new CallableTest();
    }

    public function __destruct() {
        print "DestructorTest destructor called\n";
    }
}

class CallableTest {
    public function method() {
        print "CallableTest::method() called\n";
    }
}

(new DestructorTest())->getter()->method();

打印:

DestructorTest::getter() called
DestructorTest destructor called
CallableTest::method() called

它的长短是:只要没有对象的引用,就可以调用析构函数。这甚至可以在一行中间发生 - 在这种情况下,例如,在调用DestructorTest:getter()之后,DestructorTest对象不再可访问,因此它被销毁。

我的建议:

  • 您不需要关闭MySQLi句柄。他们已经有一个内部析构函数,当它们被垃圾收集时会关闭它们。

  • 实际上:一般来说,避免编写析构函数方法。 (这适用于许多编程语言,而不仅仅是PHP。)当您期望它们时,它们通常不会被调用,并且倾向于导致奇怪的,难以调试的行为。

  • 如果您无视这一点并写了一个析构函数,那么您需要确保不会无意中破坏您已泄露的内容&# 34;提到你班级以外的人。对于您的代码,您已经允许类外部的代码获取对MySQLi句柄的引用,但是一旦您的对象消失,您就会破坏该句柄 - 即使句柄仍然存在在外面使用。