mysql_* Functions — Why They Were Removed
debt(d5/e5/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list Rector, Semgrep, and PHPStan — all specialist/SAST-category tools that must be explicitly run. The function calls are syntactically valid in PHP 5.x so no compiler error catches them; a default linter won't flag them without custom rules. On PHP 7+ they cause a fatal error at runtime (d9 side), but specialist static analysis tools bring it to d5.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions Rector's MysqlToMysqliRector for mechanical migration to mysqli_*, then a further conversion to PDO prepared statements. While Rector automates the first pass, the full remediation (converting to prepared statements, updating connection handling, adjusting error handling patterns) typically touches many files across the codebase. Not a single-line patch (e1/e3), but not a full architectural rework (e7/e9).
Closest to 'persistent productivity tax' (b5). A codebase still using mysql_* is locked to PHP ≤5.6, blocking upgrades to any modern PHP version and all its ecosystem improvements. This affects multiple workstreams (dependency updates, security patching, framework upgrades) but the burden is contained to legacy codebases — once migrated, the burden disappears entirely, so it doesn't define the system's shape permanently.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field states that mysql_real_escape_string() is believed to be a safe alternative to prepared statements, but character set attacks and certain query constructs can still bypass it. This is a serious trap: the function is named to suggest complete safety ('escape_string' implies injection prevention), yet competent developers familiar with escaping in other contexts will trust it incorrectly. The common_mistakes confirm this is the canonical wrong belief.
Also Known As
TL;DR
Explanation
The mysql extension provided functions like mysql_connect(), mysql_query(), mysql_fetch_array(), and mysql_real_escape_string(). It had two critical problems: no prepared statements, and mysql_real_escape_string() could be bypassed in certain character sets. The mysqli extension added prepared statements in PHP 5, and PDO added a clean multi-database API. mysql_* was deprecated in PHP 5.5 and removed in PHP 7.0. Any codebase still using it cannot run on PHP 7+.
Common Misconception
Why It Matters
Common Mistakes
- Using mysql_real_escape_string() believing it prevents all SQL injection
- Migrating to PHP 7 without replacing mysql_* calls (they will fatal error)
- Copy-pasting mysql_* examples from old Stack Overflow answers
Code Examples
// mysql_ extension — removed in PHP 7:
$conn = mysql_connect('localhost', 'root', '');
$result = mysql_query('SELECT * FROM users');
while ($row = mysql_fetch_array($result)) {
echo $row['name'];
}
// PDO — works across MySQL, PostgreSQL, SQLite:
$pdo = new PDO('mysql:host=localhost;dbname=app', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE active = ?');
$stmt->execute([1]);
foreach ($stmt->fetchAll() as $row) {
echo htmlspecialchars($row['name']);
}