Conexión de cierre PDO

120

Solo una pregunta bastante simple con respecto a PDO en comparación con MySQLi.

Con MySQLi, para cerrar la conexión puede hacer:

$this->connection->close();

Sin embargo, con PDO, indica que abre la conexión usando:

$this->connection = new PDO();

pero para cerrar la conexión que la configuró null.

$this->connection = null;

¿Es esto correcto y realmente liberará la conexión PDO? (Sé que funciona como está configurado null.) Quiero decir, con MySQLi tienes que llamar a una función ( close) para cerrar la conexión. ¿Es PDO tan fácil como = nulldesconectarlo? ¿O hay una función para cerrar la conexión?

Liam Sorsby
fuente
11
La razón por la que pregunto es que no estoy seguro de si estaba cerrando la conexión correctamente. pero no, no solo
estoy
2
La conexión a la base de datos se cierra automáticamente cuando su script PHP detiene la ejecución.
Martin Bean
3
Si ha terminado de usarlo, ¿por qué no continuar y terminarlo, especialmente si hay algún código que requiere mucho tiempo una vez que haya terminado de interactuar con la base de datos? Sin embargo, tampoco veo el problema de esperar a que termine el script (aparte de reducir las conexiones al servidor de base de datos)
Kieran
3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Descubra usted mismo cómo funciona: P
Flosculus
23
No todos los scripts php son de corta duración. Hay demonios php por ahí. Creo que es una gran cosa aclarar personalmente.
datUser

Respuestas:

146

De acuerdo con la documentación, estás en lo correcto ( http://php.net/manual/en/pdo.connections.php ):

La conexión permanece activa durante la vida útil de ese objeto PDO . Para cerrar la conexión, debe destruir el objeto asegurándose de que se eliminen todas las referencias restantes; para ello, asigna NULL a la variable que contiene el objeto. Si no hace esto explícitamente, PHP cerrará automáticamente la conexión cuando finalice su script .

Tenga en cuenta que si inicializa el objeto PDO como una conexión persistente, no cerrará automáticamente la conexión.

Kieran
fuente
4
¿Qué pasa si tengo un proceso que no termina? por ejemplo, websocket. ¿Hay alguna forma de no utilizar la conexión persistente?
Rafael Moni
1
Para conexiones persistentes en un script que se ejecuta durante un período prolongado, puede hacer que las conexiones se eliminen intencionalmente (o accidentalmente) con un tiempo de espera (por ejemplo, en my.ini) o por varias otras razones. Cuando conecte o ejecute una consulta, detecte cualquier error, y si es "MySQL ha desaparecido", intente conectarse de nuevo o ejecutar la consulta por segunda vez.
Frank Forte
1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionPero si una conexión es persistente y llamo explícitamente a NULL antes de que finalice el script, se cerrará incluso si es persistente, ¿correcto?
tonix
1
@tonix No, debería ser liberado (estar disponible para otro script), pero no cerrado.
Benjamin
2
@tonix Creo que sí, sí. Cita del manual de PHP sobre conexiones persistentes : " Advertencia Hay un par de advertencias adicionales que se deben tener en cuenta al usar conexiones persistentes. Una es que cuando se usa el bloqueo de tabla en una conexión persistente, si el script, por cualquier motivo, no puede liberar el bloqueo, luego, los scripts posteriores que usen la misma conexión se bloquearán indefinidamente y es posible que sea necesario reiniciar el servidor httpd o el servidor de la base de datos ".
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
fuente
11
En mi humilde opinión, creo que es un patrón muy malo, especialmente cuando un desarrollador puede almacenar varias copias de la referencia pdo. $ a = nuevo DOP (...); $ b = $ a; $ a = nulo; Allí, su objeto PDO permanecerá abierto para siempre (en un programa php similar a un demonio). Esto es especialmente cierto cuando la referencia de PDO viaja a través de funciones y propiedades de objeto, y nunca está seguro de anularlas todas.
Gabriel
33
Debería haber un método -> close () en PDO.
Gabriel
5
Otra razón para no gustarle la DOP.
José Carlos PHP
6
@Gabriel - Sugiero que "almacenar varias copias" es un patrón aún peor.
Rick James
4
Esto no funciona si ha creado un objeto PDOStatement entre esas dos filas (es decir, en todas las situaciones prácticas). Para cerrar la conexión, debe establecer tanto el objeto PDO como el objeto PDOStatement en nulo. Ver aquí: php.net/manual/en/pdo.connections.php#114822
Ilmari
8

Es más que simplemente establecer la conexión en nula. Eso puede ser lo que dice la documentación, pero esa no es la verdad para mysql. La conexión se mantendrá un poco más (he escuchado 60, pero nunca lo probé)

Si quieres aquí la explicación completa mira este comentario sobre las conexiones https://www.php.net/manual/en/pdo.connections.php#114822

Para forzar el cierre de la conexión tienes que hacer algo como

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;
Jdahern
fuente
Gracias por su respuesta. La pregunta era de hace bastante tiempo, pero tienes razón sobre la conexión.
Liam Sorsby
En realidad, no estoy de acuerdo en que jugar con la conexión TCP a través de PHP sea una buena idea. Todo el manejo de la conexión TCP de bajo nivel se abstrae para que solo tengamos que lidiar con la clase y los objetos de alto nivel durante el tiempo de ejecución. PHP es un lenguaje basado en solicitudes (como probablemente sepa), por lo que eliminar una conexión potencialmente persistente al dB probablemente resultará en errores / problemas inesperados para los usuarios. El caso de uso al que se enlaza es probablemente el resultado de que el controlador mantenga abierta la conexión persistente para que la utilice otra solicitud, por lo que habría pensado que este sería el comportamiento esperado.
Liam Sorsby
Si realmente mira la lista de procesos en mysql, mostrará que la conexión sigue ahí. Estoy de acuerdo en que no debería estar jugando con la conexión TCP de esta manera, y debería haber una manera de desconectarse de la conexión correctamente. Pero ese no es el caso. Entonces, si realmente desea desconectarse del servidor, tendrá que hacer algo como esto. Establecer la conexión en nulo no desconecta la conexión contrariamente a lo que dicen los documentos.
Jdahern
Encontré esta explicación: stackoverflow.com/a/18277327/1315873
Fil
7

Creé una clase derivada para tener una instrucción más autodocumentada en lugar 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;
    }
}

Entonces puedo llamar a mi código entre:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);
Fil
fuente
1
Puede hacer que el método CMyPDO :: __ construct () sea privado y usar el patrón singleton allí ..
Aditya Hajare
Sí, es posible. También debe asignar información de conexión mediante otro método si usa más de una base de datos a la vez. La diferencia es mínima, solo tiene instrucciones un poco más largas para llamar a métodos de instancia.
Fil
@AdityaHajare No puedes hacer que un método público de una superclase sea privado en una subclase ..
nickdnk
@nickdnk, tienes razón. Lo que quise decir fue crear una clase CMyPDO independiente (sin hacer que extienda PDO) y luego crear una instancia de base de datos dentro de un constructor privado de CMyPDO (nueva clase PDO ($ dsn, $ dbuser, $ dbpass);) asegurándose de que solo una instancia está disponible en toda la aplicación (Patrón de diseño Singleton).
Aditya Hajare
1
@Fil Pero el código "externo" closeConnectionno debe ser consciente de que necesita copiar la referencia a la variable en lugar de asignar el objeto. En otras palabras, su forma de intentar codificar una función de PDO cercana tiene efectos secundarios negativos, lo que la hace poco confiable. La única forma de hacerlo sería closeConnectionverificar cuántas referencias al objeto PDO existen en el código y arrojarlo en caso de que exista más de 1.
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

Ejemplo completo, con clase personalizada PDO2.

yo lo
fuente
1
Elimine try catch de su código o agregue un nuevo lanzamiento como se muestra aquí . En este momento, su código abusa de las excepciones y los informes de errores en general
su sentido común