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.
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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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
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
List all PHP tutorials.