PDO fechando conexão

120

Apenas uma pergunta bastante simples com relação ao PDO em comparação ao MySQLi.

Com o MySQLi, para fechar a conexão você pode fazer:

$this->connection->close();

No entanto, com PDO, afirma que você abre a conexão usando:

$this->connection = new PDO();

mas para fechar a conexão que você configurou null.

$this->connection = null;

Isso está correto e realmente liberará a conexão PDO? (Eu sei que ele faz conforme está definido null.) Quer dizer, com o MySQLi você tem que chamar uma função ( close) para fechar a conexão. O PDO é tão fácil quanto = nulldesconectar? Ou existe uma função para fechar a conexão?

Liam Sorsby
fonte
11
Estou perguntando porque não tenho certeza se fechei a conexão corretamente. mas não, não apenas intrigado
Liam Sorsby
2
A conexão do banco de dados é fechada automaticamente quando o script PHP para a execução.
Martin Bean de
3
Se você acabou de usá-lo, por que não ir em frente e encerrá-lo, especialmente se houver algum código demorado depois que você terminar de interagir com o banco de dados. Porém, eu realmente não vejo o problema em esperar a conclusão do script (além de reduzir as conexões com o servidor de banco de dados).
Kieran
3
github.com/php/php-src/blob/master/ext/pdo/pdo_dbh.c Descubra por si mesmo como funciona: P
Flosculus
23
Nem todos os scripts php têm vida curta. Existem daemons php por aí. Acho que isso é uma ótima coisa para esclarecer pessoalmente.
datUser

Respostas:

146

De acordo com a documentação, você está correto ( http://php.net/manual/en/pdo.connections.php ):

A conexão permanece ativa durante a vida útil desse objeto PDO . Para fechar a conexão, você precisa destruir o objeto , garantindo que todas as referências restantes a ele sejam excluídas - você faz isso atribuindo NULL à variável que contém o objeto. Se você não fizer isso explicitamente, o PHP fechará automaticamente a conexão quando seu script terminar .

Observe que se você inicializar o objeto PDO como uma conexão persistente, ele não fechará automaticamente a conexão.

Kieran
fonte
4
E se eu tiver um processo que não termina? por exemplo, websocket. Existe uma maneira de não usar conexão persistente?
Rafael Moni
1
Para conexões persistentes em um script que é executado por um longo período, você pode intencionalmente (ou acidentalmente) ter conexões interrompidas com um tempo limite (por exemplo, em my.ini), ou por vários outros motivos. Ao conectar ou executar uma consulta, detecte qualquer erro e, se for "O MySQL desapareceu", tente conectar novamente ou execute a consulta uma segunda vez.
Frank Forte
1
Note that if you initialise the PDO object as a persistent connection it will not automatically close the connectionMas se uma conexão for persistente e eu explicitamente chamar NULL nela antes que o script termine, ela será fechada mesmo se for persistente, correto?
tonix
1
@tonix Não, deve ser lançado (disponibilizado para outro script), mas não fechado.
Benjamin
2
@tonix acho que sim. Citação do manual do PHP sobre conexões persistentes : " Aviso Existem algumas advertências adicionais a se ter em mente ao usar conexões persistentes. Uma é que ao usar o bloqueio de tabela em uma conexão persistente, se o script por qualquer motivo não puder liberar o bloqueio, então, os scripts subsequentes que usam a mesma conexão serão bloqueados indefinidamente e podem exigir que você reinicie o servidor httpd ou o servidor de banco de dados. "
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
fonte
11
IMHO Acho que é um padrão muito ruim, especialmente quando um desenvolvedor pode armazenar várias cópias da referência de pdo. $ a = novo PDO (...); $ b = $ a; $ a = nulo; Lá, seu objeto PDO permanecerá aberto para sempre (em um programa php semelhante a um daemon). Isso é especialmente verdadeiro quando a referência PDO viaja por funções e propriedades de objeto, e você nunca tem certeza de anular todos eles.
Gabriel
33
Deve haver um método -> close () no PDO.
Gabriel
5
Outra razão para não gostar do PDO.
José Carlos PHP
6
@Gabriel - Sugiro que o “armazenamento de várias cópias” seja um padrão ainda pior.
Rick James
4
Isso não funcionará se você tiver criado um objeto PDOStatement entre essas duas linhas (ou seja, em todas as situações práticas). Para fechar a conexão, você deve definir o objeto PDO E o objeto PDOStatement como null. Veja aqui: php.net/manual/en/pdo.connections.php#114822
Ilmari
8

É mais do que apenas definir a conexão como nula. Pode ser isso que a documentação diz, mas não é verdade para o mysql. A conexão permanecerá por mais um pouco (ouvi falar dos anos 60, mas nunca testei)

Se você quiser aqui a explicação completa, veja este comentário sobre as conexões https://www.php.net/manual/en/pdo.connections.php#114822

Para forçar o fechamento da conexão, você deve fazer algo como

$this->connection = new PDO();
$this->connection->query('KILL CONNECTION_ID()');
$this->connection = null;
Jdahern
fonte
Obrigado pela sua resposta. A pergunta era de um tempo atrás, mas você está certo sobre a conexão.
Liam Sorsby de
Na verdade, não concordo que mexer com a conexão TCP via PHP seja uma boa ideia. Todo o manuseio da conexão TCP de baixo nível é abstraído de forma que apenas temos que lidar com a classe e os objetos de alto nível durante o tempo de execução. PHP é uma linguagem baseada em requisições (como você provavelmente sabe), então eliminar uma conexão potencialmente persistente com o dB provavelmente resultará em erros / problemas inesperados para os usuários. O caso de uso ao qual você se vincula provavelmente resulta no driver mantendo a conexão persistente aberta para ser utilizada por outra solicitação, portanto, pensei que esse seria o comportamento esperado.
Liam Sorsby de
Se você realmente olhar a lista de processos no mysql, ele mostrará que a conexão ainda está lá. Eu concordo que você não deve mexer com a conexão TCP assim, e deve haver uma maneira de se desconectar da conexão corretamente. Mas esse não é o caso. Portanto, se você realmente deseja se desconectar do servidor, terá que fazer algo assim. Definir a conexão como nula não desconecta a conexão ao contrário do que dizem os documentos.
Jdahern
Encontrei esta explicação: stackoverflow.com/a/18277327/1315873
Fil
7

Eu criei uma classe derivada para ter uma instrução mais autodocumentável em vez 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;
    }
}

Posso ligar para o meu código entre:

$conn=CMyPDO::getNewConnection();
// my code
CMyPDO::closeConnection($conn);
Fil
fonte
1
Você pode tornar o método CMyPDO :: __ construct () privado e usar o padrão singleton lá ..
Aditya Hajare
Sim, é possível. Você também precisa atribuir informações de conexão por outro método, se usar mais de um banco de dados ao mesmo tempo. A diferença é mínima, apenas você tem poucas instruções mais longas para chamar métodos de instância.
Fil
@AdityaHajare Você não pode tornar um método público de uma superclasse privado em uma subclasse ..
nickdnk
@nickdnk, você está certo. O que eu quis dizer era criar uma classe autônoma CMyPDO (sem torná-la estender PDO) e, em seguida, criar uma instância de banco de dados dentro de um construtor privado de CMyPDO (nova classe PDO ($ dsn, $ dbuser, $ dbpass);) certificando-se de apenas uma instância está disponível em todo o aplicativo (Singleton Design Pattern).
Aditya Hajare de
1
@Fil Mas o código "fora" closeConnectionnão deve estar ciente de que precisa copiar a referência para a variável em vez de atribuir o objeto. Em outras palavras, sua maneira de tentar codificar uma função de fechamento de PDO tem efeitos colaterais ruins, tornando-a não confiável. A única maneira de fazer isso seria closeConnectionverificar quantas referências ao objeto PDO existem no código e lançar caso mais de 1 exista.
Xenos de
-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

Exemplo completo, com classe personalizada PDO2.

yo lo
fonte
1
Remova try catch do seu código ou adicione um novo lançamento dentro, conforme mostrado aqui . No momento, seu código abusa de exceções e relatórios de erros em geral
Seu senso comum