使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)

一、那个被时代抛弃的"老朋友"

如果你维护过一些几年前的 PHP 项目,或者从网上复制过古老的教程代码,你一定对这段代码不陌生:

php

编辑

php 复制代码
1<?php
2$link = mysql_connect('localhost', 'user', 'password');
3mysql_select_db('my_database', $link);
4$result = mysql_query("SELECT * FROM users WHERE id = 1");
5$row = mysql_fetch_assoc($result);
6echo $row['username'];
7mysql_close($link);
8?>

看起来简洁明了,对吧?但在 PHP 5.5.0 版本中,这一整套 mysql_* 函数家族已经被标记为 Deprecated(废弃) ;而在 PHP 7.0.0 (2015年发布)中,它们被 彻底移除

这意味着:只要你的服务器环境升级到了 PHP 7 或更高版本(目前主流已是 PHP 8.2+),任何包含 mysql_connectmysql_query 等函数的代码都会直接抛出 Fatal error: Uncaught Error: Call to undefined function mysql_connect(),导致网站瞬间白屏,业务停摆。

这不是危言耸听,而是无数运维和开发者在深夜加班时血淋淋的教训。

二、为什么要"赶尽杀绝"?mysql_* 的三大原罪

PHP 官方之所以如此决绝地移除这些函数,并非为了折腾开发者,而是因为 mysql_* 扩展本身存在无法修复的先天缺陷:

1. 缺乏面向对象支持,架构落后

mysql_* 是过程式编程的产物,不支持面向对象(OOP)。在现代 PHP 开发中,OOP 是构建可维护、可扩展系统的基石。坚持使用过程式数据库操作,会让代码难以模块化,测试困难,且无法利用现代框架(如 Laravel, Symfony)的特性。

2. 致命短板:不支持预处理语句(Prepared Statements)

这是最严重的安全隐患。mysql_* 函数没有内置机制来防止 SQL 注入攻击

开发者必须手动转义所有输入(使用 mysql_real_escape_string),但人为疏忽无处不在。一旦忘记转义,黑客只需构造一个特殊的输入字符串,就能窃取数据库、删除表甚至控制服务器。

错误示范(极易被注入):

php

编辑

bash 复制代码
1// 危险!如果 $_GET['id'] 为 "1 OR 1=1",所有用户数据将被泄露
2$id = $_GET['id']; 
3$query = "SELECT * FROM users WHERE id = $id"; 
4$result = mysql_query($query);

而现代的 PDO 和 MySQLi 原生支持预处理语句,将 SQL 逻辑与数据分离,从根本上杜绝了此类风险。

3. 功能停滞,不再维护

mysql_* 扩展仅支持 MySQL 4.1 之前的旧特性,不支持新版本的 MySQL 功能(如事务处理的多语句支持、字符集的高级配置、存储过程的完善调用等)。自 PHP 5.5 起,该扩展已进入"维护模式",不再接收任何新功能或安全补丁。

三、救星登场:PDO vs MySQLi,该选谁?

既然 mysql_* 已死,我们该投向谁的怀抱?目前主流的两大替代方案是 PDO (PHP Data Objects)MySQLi (MySQL Improved)

表格

特性 PDO (PHP Data Objects) MySQLi
数据库支持 支持 12+ 种数据库 (MySQL, PostgreSQL, SQLite, Oracle等) 仅支持 MySQL
API 风格 纯面向对象 支持面向对象 过程式(兼容旧习惯)
预处理语句 命名参数 (:name) 或 问号占位符 (?) 仅支持问号占位符 (?)
灵活性 高,切换数据库只需改 DSN 低,绑定 MySQL
推荐指数 ⭐⭐⭐⭐⭐ (首选) ⭐⭐⭐⭐ (仅限纯 MySQL 项目)

结论 :除非你确定项目永远只绑定 MySQL 且团队极度抗拒 OOP,否则 PDO 是绝对的首选。它的通用性和命名参数特性让代码更清晰、更安全。

四、实战:如何将 mysql_* 迁移到 PDO?

光说不练假把式。下面我们将开篇的那个"僵尸代码"重构为现代化的 PDO 写法。

场景:根据 ID 查询用户信息

❌ 旧代码 (PHP 7+ 会报错)

php

编辑

php 复制代码
1<?php
2$link = mysql_connect('localhost', 'user', 'password');
3mysql_select_db('my_database', $link);
4
5// 假设 $id 来自用户输入
6$id = $_GET['id']; 
7
8// 手动转义(容易遗漏)
9$id = mysql_real_escape_string($id);
10
11$result = mysql_query("SELECT * FROM users WHERE id = $id");
12$row = mysql_fetch_assoc($result);
13
14echo $row['username'];
15mysql_close($link);
16?>

✅ 新代码 (基于 PDO,安全且兼容 PHP 8+)

php

编辑

php 复制代码
1<?php
2$dsn = 'mysql:host=localhost;dbname=my_database;charset=utf8mb4';
3$username = 'user';
4$password = 'password';
5
6$options = [
7    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // 开启异常模式
8    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // 默认关联数组
9    PDO::ATTR_EMULATE_PREPARES   => false,                  // 禁用模拟预处理,使用原生
10];
11
12try {
13    // 1. 建立连接
14    $pdo = new PDO($dsn, $username, $password, $options);
15
16    // 2. 准备语句 (Prepared Statement)
17    // 使用命名参数 :id,清晰易读
18    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
19
20    // 3. 执行并传入数据
21    // 数据会自动进行类型处理和转义,彻底杜绝 SQL 注入
22    $stmt->execute(['id' => $_GET['id']]);
23
24    // 4. 获取结果
25    $row = $stmt->fetch();
26
27    if ($row) {
28        echo htmlspecialchars($row['username'], ENT_QUOTES, 'UTF-8');
29    } else {
30        echo "用户未找到";
31    }
32
33} catch (PDOException $e) {
34    // 生产环境中不要直接输出 $e->getMessage(),应记录日志
35    error_log("Database error: " . $e->getMessage());
36    die("系统繁忙,请稍后重试");
37}
38?>

迁移关键点解析:

  1. DSN 连接字符串 :取代了 mysql_connectmysql_select_db,在一个字符串中定义主机、库名和字符集(推荐 utf8mb4 以支持 Emoji)。
  2. 异常处理 :使用 try-catch 块捕获数据库错误,而不是检查 false 返回值,代码逻辑更清晰。
  3. 预处理语句prepare() + execute() 组合。注意看 :id 占位符,无论用户输入什么恶意字符,数据库都只将其视为"数据",而非"指令"。
  4. 字符集设置 :在 DSN 中直接指定 charset=utf8mb4,避免了乱码问题。

五、给维护者的行动建议

如果你的项目中还潜伏着 mysql_* 函数,请立即采取以下行动:

  1. 全局搜索 :在 IDE 中搜索 mysql_,列出所有受影响的文件。

  2. 评估环境 :确认当前生产环境的 PHP 版本。如果是 PHP 5.x,立即制定升级计划,因为 PHP 5 早已停止安全支持。

  3. 分步重构

    • 不要试图一次性重写整个项目。
    • 创建一个通用的 Database.php 类封装 PDO 连接。
    • 按模块(如用户模块、文章模块)逐步替换旧的查询逻辑。
  4. 自动化测试:在重构前后运行测试用例,确保业务逻辑未被破坏。

  5. 锁定版本:在 Composer 或部署脚本中,强制要求 PHP 版本 >= 7.4 (推荐 8.1+),防止未来再次出现兼容性问题。

结语

技术迭代的浪潮从未停歇。mysql_* 函数的退场,标志着 PHP 生态从"草莽生长"走向了"规范安全"的成熟期。

对于开发者而言,拥抱 PDO 或 MySQLi 不仅仅是为了让代码在 PHP 7/8 上运行,更是为了构建一个更安全、更易维护、面向未来的系统。别让几行废弃的函数,成为阻碍你项目发展的绊脚石。

现在,就打开你的编辑器,开始那场迟来的"大扫除"吧!

相关推荐
苏三说技术1 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎2 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode2 小时前
Redis 在生产项目的使用
前端·后端
用户559822481222 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode3 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战3 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha3 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn3 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425913 小时前
ShardingJDBC
后端
行者全栈架构师3 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端