使用`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 上运行,更是为了构建一个更安全、更易维护、面向未来的系统。别让几行废弃的函数,成为阻碍你项目发展的绊脚石。

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

相关推荐
洛森唛2 小时前
ElasticSearch查询语句Query String详解:从入门到精通
后端·elasticsearch
用户8307196840822 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
木心月转码ing2 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
小兔崽子去哪了2 小时前
Java 自动化部署
java·后端
Selicens2 小时前
git批量删除本地多余分支
前端·git·后端
哈密瓜的眉毛美2 小时前
Java 基础补充:零基础学Java | Scanner 类详解
后端
ma_king3 小时前
入门 java 和 数据库
java·数据库·后端
平平无奇的开发仔3 小时前
Mybaitis 项目多模块多依赖xml加载classpath:和classpath*:的区别
后端
神奇小汤圆3 小时前
MySQL的10种高级SQL,性能飞升
后端