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

Prepared Statement

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

Closest to 'specialist tool catches it' (d5) — semgrep/psalm/phpstan rules flag string-interpolated queries and missing prepare()/execute() patterns, but it's not a syntax error and default linters won't catch it.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3) — quick_fix is replacing ->query("...{$var}") with ->prepare()/->execute([...]), a localised pattern swap per call site, slightly more than one line but mechanical.

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

Closest to 'localised tax' (b3) — applies to database access layer; once adopted as a convention it's lightweight, but every query site must follow the pattern across web/cli/queue contexts.

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

Closest to 'notable trap' (t5) — the misconception that PDO prepared statements are automatically safe (when ATTR_EMULATE_PREPARES is on by default) is a well-documented gotcha, plus the surprise that identifiers can't be bound.

About DEBT scoring →

Also Known As

parameterised query prepared statement SQL parameterized query

TL;DR

A parameterised SQL query where data placeholders are bound separately from the query structure, preventing SQL injection.

Explanation

A prepared statement separates the SQL structure (sent to the database first) from the data values (bound and sent separately). The database parses the query once and treats the bound values as data, never as SQL syntax — making SQL injection structurally impossible regardless of what the user submits. Both PDO (with named :param or positional ? placeholders) and MySQLi (with bind_param()) support prepared statements. Never use string concatenation to build SQL queries.

Common Misconception

Prepared statements with PDO::ATTR_EMULATE_PREPARES enabled are fully safe. Emulated prepared statements do client-side string interpolation rather than sending parameters separately to the database — disable emulation with $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false) for true parameterisation.

Why It Matters

Prepared statements are the only reliable defence against SQL injection — user data is never interpreted as SQL syntax. They also improve performance when the same query runs multiple times because the database parses it once.

Common Mistakes

  • Binding only some parameters and concatenating the rest — every external value must be bound.
  • Using PDO emulated prepares (the default) which can be bypassable — set PDO::ATTR_EMULATE_PREPARES to false.
  • Confusing query parameters with identifiers — you cannot bind table or column names, only values.
  • Reusing a statement handle but forgetting to call execute() again after changing bound values.

Code Examples

✗ Vulnerable
$id = $_GET['id'];
$rows = $pdo->query("SELECT * FROM users WHERE id = $id"); // SQLi
✓ Fixed
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);
$user = $stmt->fetch();

Added 13 Mar 2026
Edited 22 Mar 2026
Views 84
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 2 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 3 pings T 4 pings F 2 pings S 8 pings S 3 pings M 2 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 1 ping T 1 ping W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 22 Perplexity 10 Amazonbot 7 Ahrefs 7 ChatGPT 6 SEMrush 5 Google 4 Unknown AI 2 Claude 1 Bing 1 PetalBot 1
crawler 62 crawler_json 3 pre-tracking 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Replace ->query("...{$var}") with ->prepare('...:param') followed by ->execute([':param' => $var]) — the driver handles escaping automatically
📦 Applies To
PHP 5.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
->query() or ->exec() with string interpolation of variables; no prepare()/execute() pattern
Auto-detectable: ✓ Yes semgrep psalm phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-89


✓ schema.org compliant