ZetCode

PHP PDO

last modified November 14, 2026

In this tutorial we show how to program databases in PHP PDO. The examples were run with PHP 8.5 and MySQL 8.4.

PHP PDO

The PHP Data Objects (PDO) defines a lightweight interface for accessing databases in PHP. It provides a data-access abstraction layer for working with databases in PHP. It defines consistent API for working with various database systems.

PDO abstracts the way we connect to a database and execute statements. It does not rewrite SQL: the SQL dialect of each database still differs. To work with MySQL, the pdo_mysql driver is needed; on Debian and Ubuntu it is installed with the php-mysql package. The PHP mysqli tutorial covers the MySQL-specific extension, and the PHP SQLite tutorial uses PDO with SQLite.

PHP PDO classes

The PDO represents a connection between PHP and a database server. The PDOStatement represents a prepared statement and, after the statement is executed, an associated result set. The PDOException represents an error raised by PDO.

Since PHP 8.4, there are also driver-specific subclasses, such as Pdo\Mysql, Pdo\Pgsql, and Pdo\Sqlite. They hold the constants and methods that are specific to a driver. We use them in the last example.

MySQL database

In this article we work with a MySQL database named mydb and a user dbuser with the password passwd. We create them as described in the PHP mysqli tutorial. The following SQL script creates and fills the countries table.

countries_mysql.sql
DROP TABLE IF EXISTS countries;
CREATE TABLE countries(
    id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    population INT
);

INSERT INTO countries(name, population) VALUES
    ('China', 1382050000),
    ('India', 1313210000),
    ('USA', 324666000),
    ('Indonesia', 260581000),
    ('Brazil', 207221000),
    ('Pakistan', 196626000),
    ('Nigeria', 186988000),
    ('Bangladesh', 162099000),
    ('Russia', 146838000),
    ('Japan', 126830000);

These SQL commands create a countries table with ten rows. We run the script with the mysql command line tool and check the data.

$ mysql -u dbuser -p mydb < countries_mysql.sql
$ mysql -u dbuser -p mydb -e "SELECT * FROM countries"
+----+------------+------------+
| id | name       | population |
+----+------------+------------+
|  1 | China      | 1382050000 |
|  2 | India      | 1313210000 |
|  3 | USA        |  324666000 |
|  4 | Indonesia  |  260581000 |
|  5 | Brazil     |  207221000 |
|  6 | Pakistan   |  196626000 |
|  7 | Nigeria    |  186988000 |
|  8 | Bangladesh |  162099000 |
|  9 | Russia     |  146838000 |
| 10 | Japan      |  126830000 |
+----+------------+------------+

PHP PDO query

The PDO query executes an SQL statement in a single function call, returning the result set (if any) returned by the statement.

version.php
<?php

declare(strict_types=1);

$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';
$user = 'dbuser';
$passwd = 'passwd';

$pdo = new PDO($dsn, $user, $passwd);

$stm = $pdo->query('SELECT VERSION()');

$version = $stm->fetch();

echo $version[0] . PHP_EOL;

The example returns the version of MySQL.

$dsn = 'mysql:host=localhost;dbname=mydb;charset=utf8mb4';
$user = 'dbuser';
$passwd = 'passwd';

These variables are used to create a connection string to the database. The dsn is the Data Source Name, which contains the information required to connect to the database: the driver, the host, the database name, and the character set.

$pdo = new PDO($dsn, $user, $passwd);

A new PDO object is created. We pass the constructor the data source name and the user name and password. The PDO class represents a connection between PHP and a database server.

$stm = $pdo->query('SELECT VERSION()');

The query method executes an SQL statement in a single function call. It returns a PDOStatement with the result set.

$version = $stm->fetch();

The PDO statement's fetch method fetches the next row from a result set. In our case it is a version of MySQL.

echo $version[0] . PHP_EOL;

The $version is an array; we get its first value. The default fetch style returns the columns both by name and by index.

$ php version.php
8.4.11

PHP PDO error handling

Since PHP 8.0, the default error mode of PDO is PDO::ERRMODE_EXCEPTION: errors raise a PDOException. In older versions, the default was to stay silent and the programmers had to check the return values.

connect_error.php
<?php

declare(strict_types=1);

try {
    $pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'wrong-password');
} catch (PDOException $e) {
    echo get_class($e), ': ', $e->getMessage(), "\n";
}

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');
echo 'Error mode: ', $pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_EXCEPTION ? 'exceptions' : 'other', "\n";

try {
    $pdo->query('SELECT * FROM no_such_table');
} catch (PDOException $e) {
    echo 'SQLSTATE: ', $e->errorInfo[0], "\n";
    echo 'Driver code: ', $e->errorInfo[1], "\n";
    echo 'Message: ', $e->errorInfo[2], "\n";
}

The first connection fails because of a wrong password; the constructor throws a PDOException. The exception message contains the SQLSTATE code, the MySQL error number, and the server message. After a successful connection, we execute a query against a table that does not exist. The errorInfo property of the exception is an array with the SQLSTATE code, the driver specific error code, and the driver message.

In production code, the exceptions should be logged (see PHP Monolog) and not displayed to the user. An uncaught exception from the constructor can print the connection arguments, including the password, in its stack trace.

$ php connect_error.php
PDOException: SQLSTATE[HY000] [1045] Access denied for user 'dbuser'@'localhost' (using password: YES)
Error mode: exceptions
SQLSTATE: 42S02
Driver code: 1146
Message: Table 'mydb.no_such_table' doesn't exist

PHP PDO exec

The PDO exec executes an SQL statement and returns the number of affected rows. It does not return a result set, so it is suitable for INSERT, UPDATE, DELETE, and DDL statements.

affected_rows.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$nrows = $pdo->exec("INSERT INTO countries(name, population) VALUES
    ('Atlantis', 0), ('Lemuria', 0), ('Mu', 0)");

echo "The INSERT statement affected $nrows rows\n";

$nrows = $pdo->exec("DELETE FROM countries WHERE population = 0");

echo "The DELETE statement affected $nrows rows\n";

The code example inserts three rows with population zero and then deletes them again. It prints the number of affected rows each time.

$nrows = $pdo->exec("DELETE FROM countries WHERE population = 0");

In this SQL statement, we delete the rows that we have just inserted. The number of deleted rows is stored in the $nrows variable. We should never put user input into the statement passed to exec; for that we need prepared statements.

$ php affected_rows.php
The INSERT statement affected 3 rows
The DELETE statement affected 3 rows

PHP PDO fetch style

The fetch style parameter controls how the next row will be returned to the caller. For instance, the PDO::FETCH_ASSOC returns an array indexed by column name, PDO::FETCH_NUM returns an array indexed by column number, and the PDO::FETCH_BOTH returns an array indexed by both column name and indexed column number. The default fetch style is PDO::FETCH_BOTH.

PDO::FETCH_NUM

In the first code example, we get data in an indexed array.

fetch_style_num.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->query('SELECT * FROM countries LIMIT 3');

$rows = $stm->fetchAll(PDO::FETCH_NUM);

foreach ($rows as $row) {
    echo "$row[0] $row[1] $row[2]\n";
}

We select the first three rows of the countries table and pass the PDO::FETCH_NUM style to the fetchAll method. The method returns all rows as an array. We go over the $rows array and print the fields; they are accessed via array indexes.

$ php fetch_style_num.php
1 China 1382050000
2 India 1313210000
3 USA 324666000

PDO::FETCH_ASSOC

In the second example, we fetch data as an associative array.

fetch_style_assoc.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->query('SELECT * FROM countries LIMIT 3');

$rows = $stm->fetchAll(PDO::FETCH_ASSOC);

foreach ($rows as $row) {
    echo "{$row['id']} {$row['name']} {$row['population']}\n";
}

In the fetchAll method, we use the PDO::FETCH_ASSOC style. The fields are accessed by the column names, so the code does not depend on their order.

$ php fetch_style_assoc.php
1 China 1382050000
2 India 1313210000
3 USA 324666000

Other fetch styles

PDO has several other useful fetch styles. PDO::FETCH_OBJ returns an anonymous object, fetchObject and PDO::FETCH_CLASS create an object of a given class, PDO::FETCH_COLUMN returns a single column, and PDO::FETCH_KEY_PAIR returns an array in which the first column is the key and the second one the value.

fetch_styles.php
<?php

declare(strict_types=1);

class Country
{
    public int $id;
    public string $name;
    public int $population;
}

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->query('SELECT * FROM countries WHERE id = 1');
print_r($stm->fetch());

$stm = $pdo->query('SELECT * FROM countries WHERE id = 1');
$country = $stm->fetch(PDO::FETCH_OBJ);
echo $country->name, "\n";

$stm = $pdo->query('SELECT * FROM countries WHERE id = 2');
$country = $stm->fetchObject(Country::class);
var_dump($country);

$stm = $pdo->query('SELECT name FROM countries LIMIT 3');
print_r($stm->fetchAll(PDO::FETCH_COLUMN));

$stm = $pdo->query('SELECT name, population FROM countries LIMIT 3');
print_r($stm->fetchAll(PDO::FETCH_KEY_PAIR));

The first print_r shows the default PDO::FETCH_BOTH style: each value is there twice. The fetchObject(Country::class) call creates a Country object; the typed properties receive the values with the proper types. The FETCH_COLUMN style returns a flat array of names and FETCH_KEY_PAIR a map from names to populations.

$ php fetch_styles.php
Array
(
    [id] => 1
    [0] => 1
    [name] => China
    [1] => China
    [population] => 1382050000
    [2] => 1382050000
)
China
object(Country)#3 (3) {
  ["id"]=>
  int(2)
  ["name"]=>
  string(5) "India"
  ["population"]=>
  int(1313210000)
}
Array
(
    [0] => China
    [1] => India
    [2] => USA
)
Array
(
    [China] => 1382050000
    [India] => 1313210000
    [USA] => 324666000
)

Default fetch mode

Typing the fetch style in every call is tedious. We can set the default in the constructor options or later with setAttribute.

default_fetch_mode.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$stm = $pdo->query('SELECT name, population FROM countries ORDER BY population DESC LIMIT 3');

foreach ($stm as $row) {
    printf("%-10s %d\n", $row['name'], $row['population']);
}

The options array sets the error mode and the default fetch mode. The PDOStatement is traversable, so we can iterate over the rows with foreach, without calling fetch.

$ php default_fetch_mode.php
China      1382050000
India      1313210000
USA        324666000

PHP PDO parameter binding

SQL statements are often dynamically built. A user provides some input and this input is built into the statement. We must be cautious every time we deal with an input from a user. It has some serious security implications. The recommended way to dynamically build SQL statements is to use parameter binding.

PDO contains bindParam and bindValue method to create parameterized queries. PDO allows to bind data to question mark or named placeholders. The values are sent to the server separately from the statement, so they can never change its structure.

bindValue

In the first example, we use bindValue with a question mark placeholder.

parameterized_query.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$id = 3;

$stm = $pdo->prepare('SELECT * FROM countries WHERE id = ?');
$stm->bindValue(1, $id, PDO::PARAM_INT);
$stm->execute();

$row = $stm->fetch(PDO::FETCH_ASSOC);

echo "Id: " . $row['id'] . PHP_EOL;
echo "Name: " . $row['name'] . PHP_EOL;
echo "Population: " . $row['population'] . PHP_EOL;

In the example, we use bindValue to create a parameterized query. The $id variable is an input that could come from a user.

$stm = $pdo->prepare('SELECT * FROM countries WHERE id = ?');
$stm->bindValue(1, $id, PDO::PARAM_INT);
$stm->execute();

The select statement fetches a specific row from the table. We bind the value with bindValue to the question mark placeholder; the first argument is the position of the placeholder, starting from 1. The third argument is the data type.

$ php parameterized_query.php
Id: 3
Name: USA
Population: 324666000

bindParam

In the second case, we use named placeholders and bindParam.

parameterized_query2.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$id = 3;

$stm = $pdo->prepare('SELECT * FROM countries WHERE id = :id');
$stm->bindParam(':id', $id, PDO::PARAM_INT);

$stm->execute();
echo $stm->fetch(PDO::FETCH_ASSOC)['name'], "\n";

$id = 4;

$stm->execute();
echo $stm->fetch(PDO::FETCH_ASSOC)['name'], "\n";

This time we use named placeholder (:id) and bindParam. The difference is that bindParam binds a reference to the variable; the value is read at the time of execute. After changing $id, we can execute the same prepared statement again and get another row. With bindValue, the value is fixed at the time of the call.

$ php parameterized_query2.php
USA
Indonesia

execute with an array

The shortest way is to pass the values to execute in an array. Both positional and named placeholders are supported.

execute_array.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->prepare('SELECT name, population FROM countries
    WHERE population > :min AND name LIKE :pattern');
$stm->execute(['min' => 150000000, 'pattern' => '%a']);

foreach ($stm->fetchAll(PDO::FETCH_ASSOC) as $row) {
    printf("%-10s %d\n", $row['name'], $row['population']);
}

echo "---\n";

$ids = [1, 3, 5];
$placeholders = implode(', ', array_fill(0, count($ids), '?'));

$stm = $pdo->prepare("SELECT name FROM countries WHERE id IN ($placeholders)");
$stm->execute($ids);

echo implode(', ', $stm->fetchAll(PDO::FETCH_COLUMN)), "\n";

The first query uses named placeholders. In the array, the keys do not need the colon. The second query builds a list of question marks for an IN clause; the placeholders are generated from the number of values, and the values themselves are still bound. Placeholders cannot be used for table or column names; if these names come from users, they must be checked against a whitelist.

$ php execute_array.php
China      1382050000
India      1313210000
USA        324666000
Indonesia  260581000
Nigeria    186988000
---
China, USA, Brazil

Emulated prepared statements

By default, the MySQL driver emulates prepared statements: PDO substitutes the values (properly quoted) into the SQL text on the client and sends the complete statement. With PDO::ATTR_EMULATE_PREPARES set to false, the server prepares the statement natively.

emulated.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

echo 'Emulated prepares: ', var_export($pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES), true), "\n";

$stm = $pdo->prepare('SELECT name FROM countries ORDER BY id LIMIT ?');

try {
    $stm->execute([2]);
    echo implode(', ', $stm->fetchAll(PDO::FETCH_COLUMN)), "\n";
} catch (PDOException $e) {
    echo 'execute([2]) failed: ', $e->getMessage(), "\n";
}

$stm->bindValue(1, 2, PDO::PARAM_INT);
$stm->execute();
echo implode(', ', $stm->fetchAll(PDO::FETCH_COLUMN)), "\n";

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
echo 'Emulated prepares: ', var_export($pdo->getAttribute(PDO::ATTR_EMULATE_PREPARES), true), "\n";

$stm = $pdo->prepare('SELECT name FROM countries ORDER BY id LIMIT ?');
$stm->execute([2]);
echo implode(', ', $stm->fetchAll(PDO::FETCH_COLUMN)), "\n";

When execute([2]) is called, all values are bound as strings. With emulation, the statement sent to MySQL is LIMIT '2', which is a syntax error. The server cannot see the type of the value. The error goes away when we bind the value with PDO::PARAM_INT, or when we turn the emulation off; the native prepared statements accept the string. The emulation is faster for statements that are executed only once, and allows to reuse a named placeholder; native statements give stricter error checking. Both protect against SQL injection when used properly.

$ php emulated.php
Emulated prepares: true
execute([2]) failed: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''2'' at line 1
China, India
Emulated prepares: false
China, India

PHP PDO last inserted row Id

PDO lastInsertId method returns the last inserted row id.

create_table.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$pdo->exec('DROP TABLE IF EXISTS words');
$pdo->exec('CREATE TABLE words(id INT PRIMARY KEY AUTO_INCREMENT, word VARCHAR(255))');

$stm = $pdo->prepare('INSERT INTO words(word) VALUES (?)');

foreach (['pen', 'bum', 'hum', 'den'] as $word) {
    $stm->execute([$word]);
    echo "Inserted '$word' with id {$pdo->lastInsertId()}\n";
}

echo "The last inserted row id is: {$pdo->lastInsertId()}\n";

In the example, we create a new table. We insert four words with a prepared statement. After each insert, we find out the id with lastInsertId. In MySQL, the method returns the value generated for the AUTO_INCREMENT column by the last statement in the connection.

We verify the data with the mysql tool.

$ php create_table.php
Inserted 'pen' with id 1
Inserted 'bum' with id 2
Inserted 'hum' with id 3
Inserted 'den' with id 4
The last inserted row id is: 4
$ mysql -u dbuser -p mydb -e "SELECT * FROM words"
+----+------+
| id | word |
+----+------+
|  1 | pen  |
|  2 | bum  |
|  3 | hum  |
|  4 | den  |
+----+------+

PHP PDO Transactions

A transaction is an atomic unit of database operations against the data in one or more databases. The effects of all the SQL statements in a transaction can be either all committed to the database or all rolled back.

The PDO beginTransaction initiates a new transaction. The PDO commit commits the transaction. And the PDO rollBack rolls back the transaction.

transaction.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

function countCountries(PDO $pdo): int
{
    return (int) $pdo->query('SELECT COUNT(*) FROM countries')->fetchColumn();
}

echo 'Countries before: ', countCountries($pdo), "\n";

try {
    $pdo->beginTransaction();
    $pdo->exec("INSERT INTO countries(name, population) VALUES ('Iraq', 38274000)");
    $pdo->exec("INSERT INTO countries(name, population) VALUES (NULL, 37673800)");
    $pdo->commit();
} catch (PDOException $e) {
    $pdo->rollBack();
    echo 'Rolled back: ', $e->getMessage(), "\n";
}

echo 'Countries after the failed transaction: ', countCountries($pdo), "\n";

$pdo->beginTransaction();
$pdo->exec("INSERT INTO countries(name, population) VALUES ('Iraq', 38274000)");
$pdo->exec("INSERT INTO countries(name, population) VALUES ('Uganda', 37673800)");
$pdo->commit();

echo 'Countries after the successful transaction: ', countCountries($pdo), "\n";

In the example, we add new countries to the database table. The insert statements are placed in a transaction: either both inserts are executed or none.

} catch (PDOException $e) {
    $pdo->rollBack();
    echo 'Rolled back: ', $e->getMessage(), "\n";
}

In the first transaction, the second insert fails because the name column does not accept NULL values. In the catch block, we roll the transaction back; the first insert is reverted too and the number of rows does not change. In real code, we would throw the exception again so that the exception handling continues the usual way. The second transaction succeeds and adds two rows. Note that MySQL commits implicitly before DDL statements such as CREATE TABLE, so they cannot be rolled back.

$ php transaction.php
Countries before: 10
Rolled back: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null
Countries after the failed transaction: 10
Countries after the successful transaction: 12

PHP PDO getting metadata

Metadata is information about the data in a database. Metadata contains information about the tables and columns in which we store data. The number of rows that an SQL statement affects is metadata. The number of rows and columns returned in a result set are metadata as well.

Column and row count

The columnCount method returns the number of columns in the result set, and rowCount the number of rows.

column_count.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->query('SELECT name, population FROM countries WHERE id = 1');

echo "The result set contains {$stm->columnCount()} columns\n";
echo "The statement returned {$stm->rowCount()} row\n";

In the example, we print the number of columns and rows in the result set. For SELECT statements, rowCount is not guaranteed to work in all databases, but with the buffered queries of MySQL it works. It is mostly used to get the number of rows affected by UPDATE and DELETE statements.

$ php column_count.php
The result set contains 2 columns
The statement returned 1 row

Connection attributes

The getAttribute method retrieves a database connection attribute.

connection_attributes.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$server_version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
$client_version = $pdo->getAttribute(PDO::ATTR_CLIENT_VERSION);
$autocommit_mode = $pdo->getAttribute(PDO::ATTR_AUTOCOMMIT);

echo "Driver: $driver\n";
echo "Server version: $server_version\n";
echo "Client version: $client_version\n";
echo "Autocommit mode: $autocommit_mode\n";

In the example, we get the driver name, server version, client version, and autocommit mode with the getAttribute method. The client version shows that PHP uses the mysqlnd native driver.

$ php connection_attributes.php
Driver: mysql
Server version: 8.4.11
Client version: mysqlnd 8.5.12
Autocommit mode: 1

Column metadata

In the following example, we print the column metadata. The column metadata is retrieved with getColumnMeta method.

column_metadata.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd');

$stm = $pdo->query('SELECT * FROM countries WHERE id = 1');

$col_meta = $stm->getColumnMeta(0);

echo "Table name: {$col_meta['table']}\n";
echo "Column name: {$col_meta['name']}\n";
echo "Column length: {$col_meta['len']}\n";
echo "Column flags: " . implode(' ', $col_meta['flags']) . "\n";

In the example, we get the column table, name, length, and flags. The content of the returned array depends on the driver.

$ php column_metadata.php
Table name: countries
Column name: id
Column length: 20
Column flags: not_null primary_key

PHP PDO driver subclasses

Driver-specific constants such as PDO::MYSQL_ATTR_INIT_COMMAND are deprecated since PHP 8.5; they have been moved to the Pdo\Mysql class. The static PDO::connect method (PHP 8.4) creates an object of the driver-specific subclass.

driver_class.php
<?php

declare(strict_types=1);

$pdo = new PDO('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd', [
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4'",
]);
echo get_class($pdo), "\n";

$pdo = PDO::connect('mysql:host=localhost;dbname=mydb', 'dbuser', 'passwd', [
    Pdo\Mysql::ATTR_INIT_COMMAND => "SET NAMES 'utf8mb4'",
]);
echo get_class($pdo), "\n";

The first connection uses the old constant, which produces a deprecation message. The second connection uses Pdo\Mysql::ATTR_INIT_COMMAND and PDO::connect; the returned object is an instance of Pdo\Mysql. The new PDO(...) syntax keeps working and returns a plain PDO object.

$ php driver_class.php

Deprecated: Constant PDO::MYSQL_ATTR_INIT_COMMAND is deprecated since 8.5, use Pdo\Mysql::ATTR_INIT_COMMAND instead in /app/driver_class.php on line 6
PDO
Pdo\Mysql

Source

PDO - PHP manual

PDO_MYSQL - PHP manual

In this article we have programmed databases in PHP with PDO. We have connected to MySQL, handled errors, run queries and prepared statements, fetched data in several styles, used transactions and read metadata. Continue with the PHP SQLite tutorial, where PDO works with an SQLite database, and with PHP password hashing.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all PHP tutorials.