← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

PDO Introduction — Replacing mysql_* with Prepared Statements

PHP PHP 5.1+ Beginner
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep, rector, and phpstan — all specialist/SAST tools that can detect interpolated variables in PDO::query() calls or legacy mysql_* usage. These are not default linters but require deliberate configuration and tooling setup.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes replacing PDO::query($sql) with string interpolation with PDO::prepare($sql)->execute($params) — a consistent pattern replacement. While it may touch multiple call sites, each individual fix is a small mechanical refactor rather than a deep architectural change, placing it squarely at e3.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Although PDO applies to web, cli, and queue-worker contexts, the burden is localised to database-access code. Correctly migrating to prepared statements is a one-time effort that doesn't impose ongoing structural weight on the entire codebase — future maintainers inherit clean, standard patterns rather than a persistent productivity tax.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field states exactly this trap: developers believe PDO prevents SQL injection automatically regardless of usage, but PDO::query() with string interpolation is still fully vulnerable. This directly contradicts the reasonable expectation that 'switching to PDO' is sufficient for safety — a serious trap that contradicts assumptions drawn from the marketing around PDO as a 'safe' API.

About DEBT scoring →

Also Known As

PHP Data Objects PDO::prepare PDO::execute

TL;DR

PDO (PHP Data Objects), introduced in PHP 5.1, provided a unified database abstraction layer with named parameters and prepared statements — finally making SQL injection prevention structurally reliable.

Explanation

Before PDO, PHP developers used database-specific extensions: mysql_* for MySQL, pg_* for PostgreSQL. None supported named prepared statements. PDO introduced a consistent interface: PDO::prepare() creates a parameterised query, execute() runs it with bound values — the driver handles escaping internally. PDO also introduced named parameters (:name) alongside positional (?) parameters. The extension became bundled with PHP 5.1 and is the standard database interface for all modern PHP.

Common Misconception

PDO prevents SQL injection automatically regardless of how you use it — only prepared statements prevent it; PDO::query() with string interpolation is still vulnerable.

Why It Matters

PDO is the foundation of all modern PHP database interaction — understanding it explains why frameworks use it and how to use it correctly in raw PHP.

Common Mistakes

  • Using PDO::query() with interpolated variables instead of prepare/execute
  • Not checking the return value of execute() for false
  • Using ATTR_EMULATE_PREPARES without understanding it can fall back to string escaping

Code Examples

✗ Vulnerable
// mysql_ extension approach:
$result = mysql_query("SELECT * FROM users WHERE id=$id");
$row = mysql_fetch_assoc($result); // SQL injection risk + removed in PHP 7
✓ Fixed
// PDO with prepared statements:
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute([':id' => $id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);

// PDO works across MySQL, PostgreSQL, SQLite, MSSQL

Added 22 Mar 2026
Edited 23 Mar 2026
Views 34
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 7 Ahrefs 3 Perplexity 2 Google 2 Bing 2 SEMrush 2 Scrapy 2 Claude 1 Meta AI 1 Majestic 1
crawler 22 crawler_json 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Medium
⚡ Quick Fix
Replace all PDO::query($sql) with string interpolation with PDO::prepare($sql)->execute($params) — one change eliminates the entire SQL injection surface
📦 Applies To
PHP 5.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
$pdo->query("SELECT ... WHERE id='$id'") interpolation; mysql_* function calls; string concatenation building SQL
Auto-detectable: ✓ Yes semgrep rector phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Medium Context: File Tests: Update
CWE-89


✓ schema.org compliant