Connexion de fermeture PDO

121

Juste une question assez simple concernant PDO par rapport à MySQLi.

Avec MySQLi, pour fermer la connexion, vous pouvez faire:

$this->connection->close();

Cependant, avec PDO, il indique que vous ouvrez la connexion en utilisant:

$this->connection = new PDO();

mais pour fermer la connexion que vous avez définie null.

$this->connection = null;

Est-ce correct et est-ce que cela libérera réellement la connexion PDO? (Je sais qu'il fait comme il est défini null.) Je veux dire qu'avec MySQLi, vous devez appeler une fonction ( close) pour fermer la connexion. PDO est-il aussi simple que = nullde se déconnecter? Ou y a-t-il une fonction pour fermer la connexion?

Liam Sorsby
la source
11
la raison pour laquelle je demande est que je ne suis pas sûr si je fermais correctement la connexion. mais non pas vraiment juste intrigué
Liam Sorsby
2
La connexion à la base de données est automatiquement fermée lorsque votre script PHP arrête l'exécution.
Martin Bean
3
Si vous avez fini de l'utiliser, pourquoi ne pas y mettre fin, surtout s'il y a du code qui prend du temps une fois que vous avez fini d'interagir avec la base de données. Cependant, je ne vois pas vraiment le problème d'attendre la fin du script non plus (à part réduire les connexions au serveur DB.)
Kieran
3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Découvrez par vous-même comment cela fonctionne: P
Flosculus
23
Tous les scripts php ne sont pas de courte durée. Il existe des démons php. Je pense que c'est une bonne chose à clarifier personnellement.
datUser

Réponses:

146

Selon la documentation, vous avez raison ( http://php.net/manual/en/pdo.connections.php ):

La connexion reste active pendant toute la durée de vie de cet objet PDO . Pour fermer la connexion, vous devez détruire l'objet en vous assurant que toutes les références restantes à celui-ci sont supprimées - vous faites cela en affectant NULL à la variable qui contient l'objet. Si vous ne le faites pas explicitement, PHP fermera automatiquement la connexion à la fin de votre script .

Notez que si vous initialisez l'objet PDO en tant que connexion persistante, il ne fermera pas automatiquement la connexion.

Kieran
la source
4
Et si j'ai un processus qui ne se termine pas? par exemple, websocket. Existe-t-il un moyen de ne pas utiliser de connexion persistante?
Rafael Moni
1
Pour les connexions persistantes dans un script qui s'exécute pendant une longue période, vous pouvez volontairement (ou accidentellement) faire tuer des connexions avec un timeout (par exemple dans my.ini), ou pour un certain nombre d'autres raisons. Lors de la connexion ou de l'exécution d'une requête, détectez toute erreur, et si c'est "MySQL a disparu", essayez de vous connecter à nouveau ou exécutez la requête une deuxième fois.
Frank Forte
1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionMais si une connexion est persistante et que j'appelle explicitement NULL dessus avant la fin du script, elle sera fermée même si elle est persistante, n'est-ce pas?
tonix
1
@tonix Non, il devrait être publié (mis à la disposition d'un autre script), mais pas fermé.
Benjamin
2
@tonix Je pense que oui, oui. Citation du manuel PHP sur les connexions persistantes : " Avertissement Il y a quelques mises en garde supplémentaires à garder à l'esprit lors de l'utilisation de connexions persistantes. L'une est que lors de l'utilisation du verrouillage de table sur une connexion persistante, si le script pour une raison quelconque ne peut pas libérer le verrou, les scripts suivants utilisant la même connexion se bloqueront indéfiniment et peuvent nécessiter le redémarrage du serveur httpd ou du serveur de base de données. "
Benjamin
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.
himanshu dholakia
la source
11
IMHO Je pense que c'est un très mauvais modèle, surtout quand un développeur peut stocker plusieurs copies de la référence pdo. $ a = nouveau PDO (...); $ b = $ a; $ a = nul; Là, votre objet PDO restera ouvert pour toujours (dans un programme php de type démon). Cela est particulièrement vrai lorsque la référence PDO traverse des fonctions et des propriétés d'objet, et que vous n'êtes jamais sûr de les annuler toutes.
Gabriel
33
Il devrait y avoir une méthode -> close () sur PDO.
Gabriel
5
Une autre raison de ne pas aimer l'AOP.
José Carlos PHP
6
@Gabriel - Je suggère que le "stockage de plusieurs copies" est un schéma encore pire.
Rick James
4
Cela ne fonctionne pas si vous avez créé un objet PDOStatement entre ces deux lignes (c'est-à-dire dans toutes les situations pratiques). Pour fermer la connexion, vous devez définir à la fois l'objet PDO ET l'objet PDOStatement sur null. Voir ici: php.net/manual/en/pdo.connections.php#114822
Ilmari
8

C'est plus que simplement définir la connexion sur null. C'est peut-être ce que dit la documentation, mais ce n'est pas la vérité pour mysql. La connexion restera un peu plus longtemps (j'ai entendu des années 60, mais je ne l'ai jamais testée)

Si vous voulez ici l'explication complète voir ce commentaire sur les connexions https://www.php.net/manual/en/pdo.connections.php#114822

Pour forcer la fermeture de la connexion, vous devez faire quelque chose comme

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;
Jdahern
la source
Merci pour votre réponse. La question était d'il y a un certain temps, mais votre droit sur la connexion.
Liam Sorsby
Je ne suis pas d'accord pour dire que jouer avec la connexion TCP via PHP est une bonne idée. Toute la gestion de la connexion TCP de bas niveau est abstraite afin que nous ayons juste à traiter la classe et les objets de haut niveau pendant l'exécution. PHP est un langage basé sur les requêtes (comme vous le savez probablement), donc tuer une connexion potentiellement persistante au dB entraînera probablement des erreurs / problèmes inattendus pour les utilisateurs. Le cas d'utilisation auquel vous vous connectez est probablement le résultat du fait que le pilote garde la connexion persistante ouverte pour être utilisée par une autre demande, j'aurais donc pensé que ce serait le comportement attendu.
Liam Sorsby
Si vous regardez la liste des processus dans mysql, la connexion sera toujours là. Je suis d'accord que vous ne devriez pas jouer avec la connexion TCP comme ça, et il devrait y avoir un moyen de se déconnecter correctement de la connexion. Mais ce n'est pas le cas. Donc, si vous voulez vraiment vous déconnecter du serveur, vous allez devoir faire quelque chose comme ça. Définir la connexion sur null ne déconnecte pas la connexion contraty de ce que disent les documents.
Jdahern
J'ai trouvé cette explication: stackoverflow.com/a/18277327/1315873
Fil
7

J'ai créé une classe dérivée pour avoir une instruction plus auto-documentée au lieu de "$ 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;
    }
}

Je peux donc appeler mon code entre:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);
Fil
la source
1
Vous pouvez rendre la méthode CMyPDO :: __ construct () privée et y utiliser le modèle singleton ..
Aditya Hajare
Oui, c'est possible. Vous devez également attribuer des informations de connexion par une autre méthode si vous utilisez plusieurs bases de données à la fois. La différence est minime, juste vous avez peu d'instructions plus longues pour appeler les méthodes d'instance.
Fil
@AdityaHajare Vous ne pouvez pas rendre une méthode publique d'une superclasse privée dans une sous-classe ..
nickdnk
@nickdnk, vous avez raison. Ce que je voulais dire était de créer une classe autonome CMyPDO (sans la faire étendre PDO), puis de créer une instance de base de données dans un constructeur privé de CMyPDO (new PDO ($ dsn, $ dbuser, $ dbpass);) classe en s'assurant qu'un seul instance est disponible dans toute l'application (Singleton Design Pattern).
Aditya Hajare
1
@Fil Mais le code "extérieur" closeConnectionne doit pas être conscient qu'il doit copier la référence à la variable au lieu d'attribuer l'objet. En d'autres termes, votre façon d'essayer de coder une fonction PDO proche a de mauvais effets secondaires, ce qui la rend peu fiable. La seule façon de le faire serait closeConnectionde vérifier combien de références à l'objet PDO existent dans le code, et de lancer au cas où plus de 1 existe.
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

Exemple complet, avec la classe personnalisée PDO2.

Yolo
la source
1
Veuillez supprimer try catch de votre code ou ajouter un nouveau lancer à l'intérieur, comme indiqué ici . À l'heure actuelle, votre code abuse à la fois des exceptions et des rapports d'erreurs en général
Votre bon sens