PHP 7.2.0 Release Candidate 4 Released

接続、および接続の管理

PDO 基底クラスのインスタンスを作成することにより、接続が確立されます。 どのドライバを使用するのかにかかわらず、常に PDO クラスを指定します。 コンストラクタに渡す引数により、データソース (いわゆる DSN) の指定や (もしあれば、オプションで) ユーザー名およびパスワードの指定を行います。

例1 MySQL への接続

<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass);
?>

接続時になんらかのエラーが発生した場合、PDOException オブジェクトがスローされます。エラー処理を行いたい場合はこの例外を キャッチします。あるいはこれを無視して、 set_exception_handler() で設定した グローバル例外ハンドラに処理を任せることもできます。

例2 接続エラーの処理

<?php
try {
    
$dbh = new PDO('mysql:host=localhost;dbname=test'$user$pass);
    foreach(
$dbh->query('SELECT * from FOO') as $row) {
        
print_r($row);
    }
    
$dbh null;
} catch (
PDOException $e) {
    print 
"エラー!: " $e->getMessage() . "<br/>";
    die();
}
?>

警告

PDO コンストラクタからの例外をアプリケーション内でキャッチしない場合、 zend エンジンはスクリプトの実行を終了し、バックトレースを表示します。 このバックトレースを見れば、データベースへの接続の詳細がわかってしまいます。 その中にはユーザー名やパスワードも含まれます。 (catch 文を使用して) 明示的に例外をキャッチするか、 あるいは set_exception_handler() を使用して 暗黙的に例外をキャッチするようにしましょう。

データベースへの接続に成功すると、PDO クラスのインスタンスが スクリプトに返されます。この PDO オブジェクトが存在する間、 接続がアクティブであり続けます。接続を閉じるには、他から 参照されていないことを保障することでオブジェクトを破棄する 必要があります。それには、オブジェクトを保持している変数に対して NULL を代入します。 明示的にこれを行わなかった場合は、スクリプトの終了時に自動的に 接続が閉じられます。

注意: この PDO インスタンスへの参照 (PDOStatement インスタンスからの参照や、同じ PDO インスタンスを参照する別の変数からの参照など) が他にも残っているなら、それらもあわせて削除する必要があります (PDOStatement を参照する変数に NULL を代入するなど)。

例3 接続を閉じる

<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass);
// ここで接続を使用します
$sth $dbh->query('SELECT * FROM foo');

// 使用を終了したので、閉じます
$sth null;
$dbh null;
?>

データベースサーバーへの持続的な接続による恩恵をこうむる web アプリケーションは多いでしょう。持続的な接続は、スクリプトが 終了しても閉じられずにキャッシュされ、他のスクリプトが同じ内容の 接続を要求してきた際にそれが再利用されます。持続的接続の キャッシュにより、スクリプトがデータベースを使用するたびに 新しい接続を確立するオーバーヘッドを避けることができます。 それにより、結果として web アプリケーションを高速化できるように なります。

例4 持続的な接続

<?php
$dbh 
= new PDO('mysql:host=localhost;dbname=test'$user$pass, array(
    
PDO::ATTR_PERSISTENT => true
));
?>

注意:

持続的な接続を使用したい場合は、ドライバのオプションを表す配列に PDO::ATTR_PERSISTENT を設定して PDO のコンストラクタに渡す必要があります。この属性を PDO::setAttribute() を用いてインスタンス作成後に設定した場合は、 そのドライバは持続的な接続を使用しません。

注意:

PDO ODBC ドライバを使用しており、ODBC ライブラリが ODBC 接続プーリングをサポートしている場合 (unixODBC および Windows はこれをサポートしています。他にもあるかもしれません) は、 PDO の持続的接続を使用せずに ODBC の接続プーリングに 接続キャッシュ処理を任せることを推奨します。 ODBC の接続プールは、プロセス内で他のモジュールと共有されています。 PDO が接続をキャッシュしてしまうと、その接続は ODBC の 接続プールに返されなくなり、他のモジュールによって新たな接続が 作成されてしまうようになります。

add a note add a note

User Contributed Notes 11 notes

up
154
cappytoi at yahoo dot com
3 years ago
Using PHP 5.4.26, pdo_pgsql with libpg 9.2.8 (self compiled). As usual PHP never explains some critical stuff in documentation. You shouldn't expect that your connection is closed when you set $dbh = null unless all you do is just instantiating PDO class. Try following:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.1;port=5432;dbname=anydb', 'anyuser', 'pw');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM sometable');
$stmt->execute();
$pdo = null;
sleep(60);
?>

Now check your database. And what a surprise! Your connection hangs for another 60 seconds. Now that might be expectable because you haven't cleared the resultset.

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$stmt->closeCursor();
$pdo = null;
sleep(60);
?>

What teh heck you say at this point? Still same? Here is what you need to do to close that connection:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$stmt->closeCursor(); // this is not even required
$stmt = null; // doing this is mandatory for connection to get closed
$pdo = null;
sleep(60);
?>

PDO is just one of a kind because it saves you to depend on 3rd party abstraction layers. But it becomes annoying to see there is no implementation of a "disconnect" method even though there is a request for it for 2 years. Developers underestimate the requirement of such a method. First of all, doing $stmt = null  everywhere is annoying and what is most annoying is you cannot forcibly disconnect even when you set $pdo = null. It might get cleared on script's termination but this is not always possible because script termination may delayed due to slow client connection etc.

Anyway here is how to disconnect forcibly using postgresql:

<?php
$pdo
= new PDO('pgsql:host=192.168.137.160;port=5432;dbname=platin', 'cappytoi', '1111');
sleep(5);
$stmt = $pdo->prepare('SELECT * FROM admin');
$stmt->execute();
$pdo->query('SELECT pg_terminate_backend(pg_backend_pid());');
$pdo = null;
sleep(60);
?>

Following may be used for MYSQL: (not guaranteed)
KILL CONNECTION_ID()
up
5
d dot bergloev at gmail dot com
10 months ago
I would please advice people who talk about database port in reference with socket files to please read up about what a socket file is. TCP/IP uses ports, a socket file however is a direct pipe line to your database. So no, you should not replace localhost with local ip if you use a different port on your database server, because the socket file has nothing to do with your TCP/IP setup. And whenever possible, using the local socket file is much faster than establishing new TCP/IP connections on each request which is only meant for remote database servers.
up
2
me+nospam at tati dot pro
10 months ago
If you want to keep connection after fork exit, you can kill with SIGKILL forked process.

<?php
$dbh
= new PDO('pgsql:host=localhost;dbname=test', $user, $pass);
$pid = pcntl_fork();
if(
$pid == 0){
       
// forked process 'll exit immediately
       
exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);
?>
Result: false

<?php
$dbh
= new PDO('pgsql:host=localhost;dbname=test', $user, $pass);
$pid = pcntl_fork();
if(
$pid == 0){
       
// use sigkill to close process
       
register_shutdown_function(function(){
               
posix_kill(getmypid(), SIGKILL);
        });
       
// forked process 'll exit immediately
       
exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);
?>
Result: object(PDOStatement)#3 (1) {
  ["queryString"]=>
  string(8) "select 1"
}
up
11
ogierschelvis at gmail dot com
1 year ago
As http://stackoverflow.com/questions/17630772/pdo-cannot-connect-remote-mysql-server points out; sometimes when you want to connect to an external server like this:

<?php
$conn
= new PDO('mysql:host=123.4.5.6;dbname=test_db;port=3306','username','password');
?>

it will fail no matter what. However if you put a space between mysql: and host like this:

<?php
$conn
= new PDO('mysql: host=123.4.5.6;dbname=test_db;port=3306','username','password');
?>

it will magically work. I'm not sure if this applies in all cases or server setups. But I think it's worth mentioning in the docs.
up
20
neville at whitespacers dot com
8 years ago
To avoid exposing your connection details should you fail to remember to catch any exception thrown by the PDO constructor you can use the following class to implicitly change the exception handler temporarily.

<?php

Class SafePDO extends PDO {

        public static function
exception_handler($exception) {
           
// Output the exception details
           
die('Uncaught exception: ', $exception->getMessage());
        }

        public function
__construct($dsn, $username='', $password='', $driver_options=array()) {

           
// Temporarily change the PHP exception handler while we . . .
           
set_exception_handler(array(__CLASS__, 'exception_handler'));

           
// . . . create a PDO object
           
parent::__construct($dsn, $username, $password, $driver_options);

           
// Change the exception handler back to whatever it was before
           
restore_exception_handler();
        }

}

// Connect to the database with defined constants
$dbh = new SafePDO(PDO_DSN, PDO_USER, PDO_PASSWORD);

?>
up
17
jak dot spalding at gmail dot com
6 years ago
Just thought I'd add in and give an explanation as to why you need to use 127.0.0.1 if you have a different port number.

The mysql libraries will automatically use Unix sockets if the host of "localhost" is used. To force TCP/IP you need to set an IP address.
up
2
thz at plista dot com
4 years ago
If you are using PHP 5.4 and later, you can no longer use persistent connections when you have your own database class that derives from the native PDO object. If you do, you will get segmentation faults during the PHP process shutdown.

Please see this bug report for more information: https://bugs.php.net/bug.php?id=63176
up
4
dan dot franklin at pearson dot com
9 years ago
Note that you can specify a port number with "port=####", but this port number will be ignored if the host is localhost.  If you want to connect to a local port other than the default, use host=127.0.0.1 instead of localhost.
up
0
alvaro at demogracia dot com
6 years ago
On connection errors, the PDO constructor seems to do two things no matter your PDO::ATTR_ERRMODE setting:

1. Trigger a warning
2. Throw a PDOException

If you set the PDO::ATTR_ERRMODE parameter, it will only take effect on further operations.
up
-3
edsanhu at gmail dot com
1 year ago
For being able to retrieve information from the db in utf-8 the connection assignment has to add to the dsn `charset=utf8`:

<?php
$dbh
= new PDO('mysql:host=localhost;dbname=test;charset=utf8', $user, $pass);
?>
up
-13
paulo dot sistema at gmail dot com
8 months ago
Hello guys!
Has anyone used the ORACLE WALLET feature in PHP or Java?

https://docs.oracle.com/middleware/1213/wls/JDBCA/oraclewallet.htm#JDBCA596

I would like to know how to implement it because I can not implement. We use PDO + PHP in all applications and now there is this demand of the DBA.

Thank you
To Top