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

PDOStatement::bindParam() vs bindValue()

PHP PHP 5.1+ Intermediate
debt(d5/e1/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 PHPStan as the tool, and the code_pattern shows PHPStan can flag bindParam() called with literals or expressions. This is not a compiler/syntax error nor a default linter catch — it requires a static analysis tool like PHPStan configured for PDO analysis.

e1 Effort Remediation debt — work required to fix once spotted

Closest to 'one-line patch or single-call swap' (e1). The quick_fix explicitly states: use execute([$val1, $val2]) for most cases, or swap bindParam() for bindValue(). Both fixes are single-call replacements at the call site.

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

Closest to 'localised tax' (b3). The applies_to covers web and cli contexts broadly, but the actual burden is localised to database query code. Once corrected, the rest of the codebase is unaffected. It does not impose a systemic cross-cutting tax.

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

Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field states developers believe bindParam() and bindValue() are interchangeable, but bindParam() binds by reference and evaluates at execute() time — the opposite of what most developers expect. This contradicts intuition from similar parameter binding APIs in other languages/ORMs and causes silent wrong-value bugs in loops, making it a serious behavioural trap.

About DEBT scoring →

Also Known As

PDO bindParam PDO bindValue bind placeholder PDO

TL;DR

Two PDO methods for binding variables to placeholders — bindParam() binds by reference (evaluated at execute), bindValue() binds by value (evaluated immediately).

Explanation

bindParam($placeholder, $var, $type) binds a variable by reference — the current value at execute() time is used. bindValue($placeholder, $val, $type) binds the value immediately — changing $val later has no effect. bindParam() is useful in loops where the variable changes between iterations. The $type parameter (PDO::PARAM_INT, PDO::PARAM_STR, PDO::PARAM_BOOL, PDO::PARAM_NULL) enforces type safety. Most developers use execute([$val]) shorthand — equivalent to bindValue for most cases.

Common Misconception

bindParam() and bindValue() are interchangeable. bindParam() evaluates the variable at execute() time (by reference). Using bindParam() on a temporary expression causes a PHP warning.

Why It Matters

The execute([]) shorthand binds all values as PDO::PARAM_STR — for integer IDs in certain configurations this matters for query plan efficiency. Explicit bindParam/bindValue with PDO::PARAM_INT helps the query optimiser in edge cases.

Common Mistakes

  • Using bindParam() with a loop variable that doesn't change — execute() always sees the same value.
  • Passing PDO::PARAM_INT for a column that stores NULL — use PDO::PARAM_NULL or check before binding.
  • Over-using explicit bind calls when execute([]) is cleaner and sufficient.

Avoid When

  • Do not use bindParam() with a literal value or expression — PHP cannot bind non-variables by reference.
  • Avoid explicit bind calls when execute([$val]) shorthand is cleaner — they are equivalent for most cases.

When To Use

  • Use bindParam() when reusing a prepared statement in a loop with a variable that changes each iteration.
  • Use bindValue() with PDO::PARAM_INT when type safety matters for the query optimiser.

Code Examples

✗ Vulnerable
// bindParam on literal/expression — PHP warning
$stmt->bindParam(':id', 42); // Cannot bind non-variable by reference
$stmt->bindParam(':id', $a + $b); // Same issue
✓ Fixed
// execute([]) shorthand — cleaner for simple cases
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->execute([$userId]);

// bindParam in loop — variable changes each iteration
$stmt = $pdo->prepare('INSERT INTO tags (name) VALUES (?)');
$stmt->bindParam(1, $tagName); // bound by reference
foreach ($tags as $tagName) {
    $stmt->execute(); // $tagName value used at each execute()
}

// bindValue with type
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bindValue(1, $userId, PDO::PARAM_INT);
$stmt->execute();

Added 31 Mar 2026
Views 146
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 5 pings T 2 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 2 pings S 4 pings M 3 pings T 0 pings W 1 ping T 3 pings F 1 ping S 2 pings S 1 ping M 0 pings T 1 ping W 1 ping T 1 ping F
PetalBot 1
Brave Search 1
ChatGPT 71 Perplexity 16 Google 10 Ahrefs 4 PetalBot 4 Unknown AI 3 Bing 3 Meta AI 2 NotebookLM 2 Scrapy 2 Majestic 1 Twitter/X 1 SEMrush 1 Applebot 1 Brave Search 1
crawler 118 crawler_json 3 pre-tracking 1
🧱 FUNDAMENTALS — new to this? Start with the ground floor.
PHP php A server-side scripting language that generates web pages and APIs — the code runs on the server, and only its output (usually HTML or JSON) reaches the browser.

PHP is often the first server-side language people meet, and understanding its execution model — script starts fresh on every request, no memory between requests — explains most of how the web backend works: sessions, databases, and caching all exist to bridge that per-request amnesia.

💡 Start with PHP 8.x, declare(strict_types=1), and PDO — skip any tutorial that mentions mysql_query().

Ask Codex about PHP →
DEV INTEL Tools & Severity
⚙ Fix effort: Low
⚡ Quick Fix
Use execute([$val1, $val2]) for most cases — use bindParam() when reusing a statement in a loop with a changing variable
📦 Applies To
PHP 5.1+ web cli
🔗 Prerequisites
🔍 Detection Hints
bindParam(':id', 42) or bindParam(':x', $a + $b) — literals/expressions
Auto-detectable: ✓ Yes phpstan
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line


✓ schema.org compliant