Databases Introduction
Almost every real PHP application needs to remember things between requests: user accounts, blog posts, orders, comments. PHP itself has no memory from one page load to the next — each request starts a fresh process that forgets everything once it finishes. A database is what gives an application persistent, shared storage that every request can read from and write to, whether that request comes from the same visitor a minute later or a completely different visitor on the other side of the world. This page is the on-ramp for the rest of the database section: it explains the two extensions PHP ships for talking to a relational database, and why one of them is worth reaching for by default.
Two built-in ways to talk to a database
PHP does not force you to install a third-party library just to run a SQL query. Two extensions are commonly available out of the box (or via a very common PHP extension install):
mysqli— "MySQL Improved". Works only with MySQL and MariaDB, offers both a procedural and an object-oriented API.PDO(PHP Data Objects) — a database-agnostic abstraction layer that works with MySQL, PostgreSQL, SQLite, SQL Server, and others through interchangeable drivers.
Both extensions can run plain queries and both support prepared statements, which is the mechanism that keeps user input from being interpreted as SQL code (covered in full on the prepared statements page). The real difference between them is scope and consistency, not security.
Why PDO is the usual default
PDO is generally the recommended starting point for new PHP code, for a few concrete reasons rather than fashion:
Database-agnostic — the same
PDOobject and method calls work against MySQL, PostgreSQL, or SQLite; switching databases mostly means changing the connection string, not rewriting queries.One consistent API —
->prepare(),->execute(), and->fetch()behave the same way regardless of which driver is underneath, so there is less to remember and less that changes if a project ever migrates databases.Native prepared statements — parameter binding is a first-class part of the API, not something bolted on.
Flexible error handling —
PDOcan be configured to throw real exceptions on failure, so database errors fit naturally into normal try/catch code instead of needing to be checked after every call.
mysqli | PDO | |
|---|---|---|
Databases supported | MySQL / MariaDB only | MySQL, PostgreSQL, SQLite, SQL Server, and more |
API style | Procedural or object-oriented | Object-oriented only |
Prepared statements | Yes | Yes |
Named placeholders | No | Yes |
Typical use today | Legacy MySQL-only codebases | New projects, especially anything that might need portability |
How a query actually reaches the database
It helps to picture the layers a query passes through before a row of data ever comes back to your PHP script. Your application code never talks to the database file or server directly — it always goes through an extension and a driver:
Request path for a database query
Your PHP code
|
| $pdo->query('SELECT ...') or $pdo->prepare(...)->execute(...)
v
PDO (or mysqli) extension <- consistent PHP-facing API
|
v
Database driver (pdo_mysql, pdo_pgsql, pdo_sqlite, ...)
|
| translates calls into the database's wire protocol
v
Database server (MySQL, PostgreSQL, ...) or database file (SQLite)Because the driver is the layer that actually knows how to speak MySQL's or PostgreSQL's wire protocol, swapping pdo_mysql for pdo_pgsql in the connection string is often the only change needed to move an application's queries onto a different database engine — as long as the SQL itself doesn't rely on syntax that's specific to one vendor.
Connecting with each extension, at a glance
The connection setup for each extension looks different, but they both end with an object you'll call query methods on.
mysqli (object-oriented style)
<?php
$mysqli = new mysqli('localhost', 'app_user', 'secret', 'shop');
if ($mysqli->connect_errno) {
die('Connection failed: ' . $mysqli->connect_error);
}PDO
<?php
$dsn = 'mysql:host=localhost;dbname=shop;charset=utf8mb4';
try {
$pdo = new PDO($dsn, 'app_user', 'secret', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
} catch (PDOException $e) {
die('Connection failed: ' . $e->getMessage());
}