PHP PDO关闭连接设置为null但返回语句

时间:2019-01-30 15:42:25

标签: php pdo database-connection

我创建了一个连接数据库的类。然后,所有其他类都可以使用此类中的connect函数来打开与DB的连接。在函数末尾,我返回结果。那么返回结果后如何关闭连接?

<?php

class DbhPdo {
  private $servername;
  private $username;
  private $pwd;
  private $dbname;

  protected function connect() {
    $this->servername = "localhost";
    $this->username = "someUser";
    $this->pwd = "somePswd";
    $this->dbname = "someDB";
    $this->charset = "utf8mb4";

    try{
      $dsn = "mysql:host=" . $this->servername . ";dbname=" . $this->dbname . ";charset=" . $this->charset;
      $pdo = new PDO($dsn, $this->username, $this->pwd);
      $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      return $pdo;
    } catch(PDOException $e) {
      echo "Message: " . $e->getMessage();
    }
  }
}

如果在返回后设置以下内容,则永远不会调用它来关闭连接:

$pdo = null;

还是PDO会自动关闭此连接,因为它是在执行完命令-返回$ pdo之后完成的?

还是我必须在扩展连接的类中关闭连接?

以下是扩展上述类的类,但是我也在该类中返回结果,因此在这里我也无法将stmt设置为null:

<?php

require_once('dbh.pdo.inc.php');

class LoginPdo extends DbhPdo {
  public $name;
  public $pass1;
  public $hashed;
  public $salted;


  protected function getSomething($name) {
    try{
      $stmt = $this->connect()->query("select something from table where name ='" . $name . "'");
      return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }catch (PDOException $e){
      echo 'Message: ' . $e->getMessage();
    }
  }
}

哪个离开了开始该课程的原始类:

  try{
    $this->result = $this->getSomething($this->name);
    echo json_encode($this->result);
    $this->result = null;
  }catch (PDOException $e){
    echo 'Message: ' . $e->getMessage();
  }

是否要设置$ this-> result = null来关闭连接?如果是这样,那么我听不懂。有人可以向我解释吗?还是在设置$ pdo = null时正确理解它是我需要关闭连接的地方?

如果是这样,那么如何在执行返回$ pdo之后将其设置为null?

预先感谢

更新: 以防万一其他人希望能够验证连接是否关闭,这些是我用来确认@ Don'tPanic注释以尾随常规日志文件的步骤:

mysql -u root -p
show variables like '%log%';
set global general_log=ON;

tail -f /usr/local/mysql/data/<your log file's name>.log

然后显示连接,当我使用PostMan发布以下查询时立即打开和关闭:

190130 11:00:17  2581 Query show variables like '%log%'
190130 11:02:14  2582 Connect   root@localhost on <table name>
    2582 Query  select * from something where name ='whatever'
    2582 Quit

这是通过遵循@ Don'tPanic答案在DbhPdo类中添加新功能来实现的:

protected function disconnect() {
  $this->pdo = null;
}

然后我添加了$ this-> pdo = null;回声后json_encode($ this-> result);

感谢您的所有评论

2 个答案:

答案 0 :(得分:1)

将结果设置为null不会将连接设置为null。

实际上并不一定需要显式关闭连接,但是如果您希望能够做到这一点,则需要将其设置为null。您必须对连接有一些引用,并且当前方法不会将该引用存储在任何地方。将连接定义为类的属性将为您解决这个问题。

我修改了您的connect函数以显示示例。

基本上,不是仅返回连接,而是检查现有连接并返回,或者如果尚未建立连接,则建立新连接,但是重要的是设置属性$this->pdo来代替使用仅存在于connect函数范围中的$pdo变量的说明。

// ...
private $pdo;

protected function connect() {
    // I suggest setting these in the constructor rather than hard coding them here
    // $this->servername = "localhost";
    // $this->username = "someUser";
    // $this->pwd = "somePswd";
    // $this->dbname = "someDB";
    // $this->charset = "utf8mb4";

    if ($this->pdo) {
        return $this->pdo;
    else {
        try{
            $dsn = "mysql:host=" . $this->servername . ";dbname=" . $this->dbname . ";charset=" . $this->charset;
            $this->pdo = new PDO($dsn, $this->username, $this->pwd);
            $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            return $this->pdo;
        } catch(PDOException $e) {
            echo "Message: " . $e->getMessage();
        }
    }
}

设置$this->pdo而不只是在connect函数中使用局部变量将为您提供一些可以设置为null断开连接的功能。

protected function disconnect() {
    $this->pdo = null;
}

您可以在执行请求所需的所有查询后调用disconnect()。如果在此之前断开连接,则必须重新连接以运行其他查询,这是不必要的,并且会损害应用程序的性能。

答案 1 :(得分:0)

您的PDO API实例是从$this->connect()返回的。这是您使用的唯一实例。如果要保存状态以供以后使用或关闭,则可以使用:

$stmt = ($con =& $this->connect())->query(...);
$con  = null; # Or use the instance else where
return $stmt->fetchAll(PDO::FETCH_ASSOC);

如果PDOPrepareStatement通过引用使用PDO实例,则可以使用clone复制实例,而不是写入实例。

$stmt = ($con =& clone $this->connect())->query(...);

您的$stmt变量是PDOPrepareStatement,因为PDO::query不会返回PDO实例,因此,您已经将其设置为null。

要注意的一点:如果要构建模型,则应考虑设计单例方法。您可以查看example I made for Laravel

trait Singleton
{
    private static $instance;

    public static function getInstance()
    {
        return self::$instance ?? (self::$instance = new self());
    }

    //
}

然后您可以创建自己的超级模型:

class Model
{
    use Singleton;

    protected $pdo;

    public function __construct()
    {
        // instance your PDO
    }

    public function select()
    {
        // super method all models can use
    }
}

然后只需创建模型!

class UserModel extends Model
{
    public function find($id)
    {
        return $this->select(...)->fetch();
    }
}

您可以像这样使用它:

UserModel::getInstance()
    ->find(1);