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

bind_param()

php PHP 5.1+ Intermediate
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 phpstan and semgrep as the tools, and automated detection is marked yes — these are specialist static analysis tools rather than default linters or compilers. The code_pattern notes type mismatches and wrong binding contexts, which require semantic analysis beyond a basic linter.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix states switching to PDO's bindValue() or restructuring to PDO named placeholders — this is a pattern-level replacement within a component (swap mysqli prepared statements for PDO equivalents) rather than a single-line patch or an architectural rework. It may touch multiple queries but is locally contained.

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

Closest to 'localised tax' (b3). bind_param() applies across web, cli, and queue-worker contexts per applies_to, but its reach is limited to the data-access layer. It doesn't bleed into every part of the codebase — only code that interacts directly with the database bears the tax. Future maintainers need to understand the reference semantics but it doesn't reshape the whole system.

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

Closest to 'serious trap' (t7). The misconception field explicitly states that bind_param() binds by reference (value read at execute() time), directly contradicting PDO's bindValue() which captures immediately. Developers familiar with PDO will confidently apply the wrong mental model, causing subtle loop-binding bugs. This is a documented behavioural contradiction across similar concepts in the same ecosystem, warranting t7.

About DEBT scoring →

Also Known As

bind_param() mysqli bind prepared statement binding

TL;DR

MySQLi method that binds PHP variables to prepared statement parameters, preventing SQL injection.

Explanation

mysqli_stmt::bind_param(string $types, mixed &...$vars) associates PHP variables with the ? placeholders in a prepared MySQLi statement. The type string must have one character per variable: s (string), i (integer), d (double/float), b (blob). Values are transmitted to the database separately from the query, making injection impossible. Must be called after prepare() and before execute().

Common Misconception

bind_param() is interchangeable with PDO bindValue(). bind_param() binds by reference — the variable value is read at execute() time, not at bind time. PDO's bindValue() captures the value immediately. This distinction causes subtle bugs when binding inside loops.

Why It Matters

bind_param() binds variables to prepared statement placeholders by reference — misunderstanding the binding semantics or type strings leads to subtle bugs or SQL injection.

Common Mistakes

  • Using the wrong type character: 's' for string, 'i' for integer, 'd' for double, 'b' for blob — a mismatch causes incorrect binding.
  • Not understanding that bind_param() binds by reference — changing the variable after binding changes what gets sent.
  • Using bind_param() with a dynamic number of parameters without call_user_func_array() or spread — directly concatenating SQL is SQLi.
  • Choosing mysqli over PDO for new code — PDO named placeholders (:name) are clearer and less error-prone than positional binding.

Code Examples

✗ Vulnerable
// Wrong type string — 's' used for integer column:
$stmt = $conn->prepare('SELECT * FROM users WHERE id = ?');
$stmt->bind_param('s', $id); // Should be 'i' for integer

// Dynamic params without spread — common but verbose:
$types = str_repeat('s', count($values));
$stmt->bind_param($types, ...$values);
✓ Fixed
// Type chars: s=string, i=integer, d=double, b=blob
\$stmt = \$db->prepare('INSERT INTO products (name, price, stock) VALUES (?, ?, ?)');
\$stmt->bind_param('sdi', \$name, \$price, \$stock);

\$name  = 'Widget';
\$price = 9.99;
\$stock = 100;
\$stmt->execute();

// Reuse same statement for multiple rows:
\$stmt = \$db->prepare('INSERT INTO tags (name) VALUES (?)');
\$stmt->bind_param('s', \$tag);
foreach (['php', 'security', 'mysql'] as \$tag) {
    \$stmt->execute(); // \$tag bound by reference — updates each iteration
}
\$stmt->close();

Added 15 Mar 2026
Edited 22 Mar 2026
Views 33
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 2 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 3 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 8 Perplexity 8 Unknown AI 3 Ahrefs 2 SEMrush 2 ChatGPT 2 Google 1
crawler 24 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Use PDO's bindValue() for immediate binding or bindParam() when you need to rebind a variable before each execute — prefer PDO over mysqli for modern PHP code
📦 Applies To
PHP 5.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
mysqli_bind_param in new code; binding wrong type for integer columns causing type juggling issues; using PDO::PARAM_STR for integer IDs
Auto-detectable: ✓ Yes phpstan semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line
CWE-89

✓ schema.org compliant