Подключения и Управление подключениями
Соединения устанавливаются автоматически при создании объекта 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 "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
Если ваше приложение не перехватывает исключение PDO конструктора, движок zend выполнит стандартные операции для завершения работы скрипта и вывода обратной трассировки. В этой трассировке будет содержаться детальная информация о соединении с базой данных, включая имя пользователя и пароль. Ответственность за перехват исключений лежит на вас. Перехватить исключение можно явно (с помощью выражения catch), либо неявно, задав глобальный обработчик ошибок функцией set_exception_handler().
При успешном подключении к базе данных в скрипт будет возвращен созданный
PDO объект. Соединение остается активным на протяжении всего времени жизни
объекта. Чтобы закрыть соединение, необходимо уничтожить объект путем удаления
всех ссылок на него (этого можно добиться, присваивая NULL
всем переменным,
указывающим на объект). Если не сделать этого явно, PHP автоматически
закроет соединение по окончании работы скрипта.
Пример #3 Закрытие соединения
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
// здесь мы каким-то образом используем соединение
// соединение больше не нужно, закрываем
$dbh = null;
?>
Во многих приложениях может оказаться полезным использование постоянных соединений к базам данных. Постоянные соединения не закрываются при завершении работы скрипта, они кэшируются и используются повторно, когда другой скрипт запрашивает соединение с теми же учетными данными. Постоянные соединения позволяют избежать создания новых подключений каждый раз, когда требуется обмен данными с базой, что в результате дает прирост скорости работы таких приложений.
Пример #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 Connection Pooling) (unixODBC и Windows точно поддерживают, но могут быть и другие), то рекомендуется вместо постоянных соединений пользоваться этим пулом. Пул подключений ODBC доступен всем модулям текущего процесса; если PDO сам кэширует соединение, то это соединение будет недоступно другим модулям и не попадет в пул. В результате каждый модуль будет создавать дополнительные подключения для своих нужд.
Коментарии
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.
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);
?>
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.
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.
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
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()
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);
?>
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.
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.
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"
}
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
Please note that you cannot use persistent connections to create temporary tables in mysql/mariadb.
Tables you create using a statement like "create temporary table TABLE1 ..." are destroyed only when the mysql session ends (not php session !). This never happens if you use a persistent connection.
If you create a temporary table on a persistent connection, the table will live even after the php script ends. The next php script that will try to issue the same create temporary table statement, will receive an error.
IMHO, this fact makes persistent connections quite useless.
It's not possible to use a persistent connection and to extend the PDOStatement class to add methods to the standard class. This means that you cannot do:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$dbh->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement', array($this)));
?>
This results in an error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances