PDOが接続を閉じる


120

MySQLiと比較して、PDOに関してはかなり単純な質問です。

MySQLiでは、接続を閉じるには次のようにします。

$this->connection->close();

ただし、PDOでは、次を使用して接続を開くと記載されています。

$this->connection = new PDO();

接続を閉じるには、に設定しnullます。

$this->connection = null;

これは正しいですか?これは実際にPDO接続を解放しますか?(私はそれがに設定されているのでそれを知っていnullます。)closeつまり、MySQLiでは、接続を閉じるために関数()を呼び出す必要があります。PDOは= null切断するのと同じくらい簡単ですか?または、接続を閉じる機能はありますか?


11
私が尋ねている理由は、接続を適切に閉じていたかどうかわからないからです。しかし、何ではないん実際には興味をそそら
リアムSorsby

2
PHPスクリプトが実行を停止すると、データベース接続は自動的に閉じられます。
Martin Bean

3
それを使い終わったら、特にデータベースとのやり取りが終わって時間がかかるコードがある場合は特に、それを終了しないでください。けれども、私は本当にかかわらず、いずれかの仕上げにスクリプトを待っていると、問題が表示されない(DBサーバーへの接続を削減する以外。)
キーラン


23
すべてのphpスクリプトが短命ではありません。そこにPHPデーモンがあります。これは個人的にはっきりさせておくには素晴らしいことだと思います。
datUser 2014年

回答:


146

ドキュメントによると、あなたは正しいです(http://php.net/manual/en/pdo.connections.php):

接続は、そのPDOオブジェクトの存続期間中アクティブのままです。接続を閉じるには、オブジェクトへの残りの参照をすべて削除して、オブジェクト破棄する必要があります。これを行うには、オブジェクトを保持する変数にNULLを割り当てます。これを明示的に行わないと、PHPはスクリプトが終了すると自動的に接続を閉じます

PDOオブジェクトを永続的な接続として初期化しても、接続は自動的に閉じられないことに注意してください。


4
終了しないプロセスがある場合はどうなりますか?例:websocket。永続的な接続を使用しない方法はありますか?
Rafael Moni

1
長期間実行されるスクリプトの永続的な接続の場合、意図的に(または誤って)タイムアウトで接続を切断することができます(たとえば、my.iniで)、または他のいくつかの理由。クエリを接続または実行するときにエラーをキャッチし、それが「MySQLがなくなった」場合は、再度接続するか、クエリをもう一度実行してみます。
フランクフォルテ2017

1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionしかし、接続が永続的で、スクリプトが終了する前に明示的にNULLを呼び出すと、永続的であっても閉じられますよね?
tonix 2018年

1
@tonixいいえ、リリースする必要があります(別のスクリプトで利用可能にする)必要がありますが、閉じないでください。
ベンジャミン

2
@tonixそうだと思います。永続的な接続に関するPHPマニュアルからの引用:" 警告永続的な接続を使用する場合は、いくつかの追加の注意点があります。永続的な接続でテーブルロックを使用する場合、なんらかの理由でスクリプトがロックを解除できない場合、その後、同じ接続を使用する後続のスクリプトは無期限にブロックされ、httpdサーバーまたはデータベースサーバーの再起動が必要になる場合があります。」
ベンジャミン

46
$conn=new PDO("mysql:host=$host;dbname=$dbname",$user,$pass);
    // If this is your connection then you have to assign null
    // to your connection variable as follows:
$conn=null;
    // By this way you can close connection in PDO.

11
私見これは非常に悪いパターンだと思います。特に、開発者がpdo参照のコピーをいくつか保存する場合はそうです。$ a =新しいPDO(...); $ b = $ a; $ a = null; そこでは、PDOオブジェクトは(デーモンのようなphpプログラムで)永久に開いたままになります。これは、PDO参照が関数とオブジェクトプロパティを移動するときに特に当てはまり、それらすべてをnullにすることが確実ではありません。
ガブリエル

33
PDOには-> close()メソッドが必要です。
ガブリエル

5
PDOを嫌うもう1つの理由。
ホセカルロスPHP

6
@Gabriel-「複数のコピーを保存する」ことはさらに悪いパターンだと思います。
リックジェームズ

4
これらの2つの行の間にPDOStatementオブジェクトを作成した場合(つまり、あらゆる実際的な状況で)、これは機能しません。接続を閉じるには、PDOオブジェクトとPDOStatementオブジェクトの両方をnullに設定する必要があります。こちらをご覧ください:php.net/manual/en/pdo.connections.php#114822
Ilmari

8

接続をnullに設定するだけでは不十分です。それはドキュメントが言うことかもしれませんが、それはmysqlの真実ではありません。接続は少し長く続きます(60年代は聞いたことがありますが、テストしていません)

ここで完全な説明が必要な場合は、接続に関するこのコメントを参照してくださいhttps://www.php.net/manual/en/pdo.connections.php#114822

接続を強制的に閉じるには、次のようにする必要があります

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;

お返事ありがとうございます。問題はかなり前からでしたが、接続についてのあなたの権利です。
Liam

PHP経由のTCP接続をいじるのは良い考えだと私は実際には同意しません。すべての低レベルのTCP接続処理は抽象化されているため、実行時に高レベルのクラスとオブジェクトを処理するだけで済みます。PHPはリクエストベースの言語です(おそらくご存じのとおり)。dBへの永続的な接続を強制終了すると、ユーザーに予期しないエラー/問題が発生する可能性があります。リンク先のユースケースは、ドライバーが永続的な接続を開いたままにして別のリクエストで利用できるようにする結果である可能性が高いため、これは予想される動作と考えられます。
Liam Sorsby

実際にmysqlのプロセスリストを見ると、そこにはまだ接続が表示されます。このようなTCP接続をごちゃごちゃにしないでください。接続から適切に切断する方法があるはずです。しかし、そうではありません。したがって、本当にサーバーから切断したい場合は、次のようにする必要があります。接続をnullに設定しても、ドキュメントの内容に反する接続は切断されません。
Jdahern

私はこの説明を見つけました:stackoverflow.com/a/18277327/1315873
フィル

7

「$ conn = null;」の代わりに、より自己文書化する命令を持つ派生クラスを作成しました。

class CMyPDO extends PDO {
    public function __construct($dsn, $username = null, $password = null, array $options = null) {
        parent::__construct($dsn, $username, $password, $options);
    }

    static function getNewConnection() {
        $conn=null;
        try {
            $conn = new CMyPDO("mysql:host=$host;dbname=$dbname",$user,$pass);
        }
        catch (PDOException $exc) {
            echo $exc->getMessage();
        }
        return $conn;
    }

    static function closeConnection(&$conn) {
        $conn=null;
    }
}

だから私は私のコードを次の間に呼び出すことができます:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);

1
あなたは...そこにパターンシングルトンプライベートで使用CMyPDO :: __構築物()メソッドを作ることができます
アーディティヤHajare

はい、可能です。同時に複数のデータベースを使用する場合は、別の方法で接続情報を割り当てる必要もあります。違いはごくわずかで、インスタンスメソッドを呼び出すための命令が少し長くなっただけです。
2017年

@AdityaHajareスーパークラスのパブリックメソッドをサブクラスでプライベートにすることはできません
。– nickdnk

@nickdnk、あなたは正しい。私が意味したのは、スタンドアロンクラスCMyPDO(PDOを拡張せずに)を作成し、次にCMyPDO(新しいPDO($ dsn、$ dbuser、$ dbpass);)クラスのプライベートコンストラクター内にデータベースのインスタンスを作成して、1つだけを確認することでした。インスタンスはアプリケーション全体で使用できます(シングルトンデザインパターン)。
Aditya Hajare 2017年

1
@Filしかし、「外部」のコードcloseConnectionは、オブジェクトを割り当てるのではなく、変数への参照をコピーする必要があることを認識してはなりません。言い換えると、近いPDO関数をコーディングしようとする方法には悪影響があり、信頼性が低くなります。これを行う唯一の方法closeConnectionは、コード内にPDOオブジェクトへの参照がいくつ存在するかを確認し、複数存在する場合にスローすることです。
Xenos

-1
<?php if(!class_exists('PDO2')) {
    class PDO2 {
        private static $_instance;
        public static function getInstance() {
            if (!isset(self::$_instance)) {
                try {
                    self::$_instance = new PDO(
                        'mysql:host=***;dbname=***',
                        '***',
                        '***',
                        array(
                            PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_general_ci",
                            PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION
                        )
                    );
                } catch (PDOException $e) {
                    throw new PDOException($e->getMessage(), (int) $e->getCode());
                }
            }
            return self::$_instance;
        }
        public static function closeInstance() {
            return self::$_instance = null;
        }
    }
}
$req = PDO2::getInstance()->prepare('SELECT * FROM table');
$req->execute();
$count = $req->rowCount();
$results = $req->fetchAll(PDO::FETCH_ASSOC);
$req->closeCursor();
// Do other requests maybe
// And close connection
PDO2::closeInstance();
// print output

カスタムクラスPDO2を使用した完全な例。


1
コードからtry catchを削除するか、ここに示すように内部に新しいスローを追加してください。現在、コードは一般的に例外とエラー報告の両方を乱用しています
常識
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.