php 7+ 彻底移除 mysql 扩展,必须改用 mysqli 或 pdo;连接后须显式设 utf8mb4 字符集;防 sql 注入唯一可靠方式是预处理语句;pdo 比 mysqli 更具数据库可移植性与错误处理优势。

mysql_connect() 在 PHP 7+ 直接报错,不是警告而是彻底消失
你看到 Fatal error: Uncaught Error: Call to undefined function mysql_connect(),不是配置没开、不是扩展没装——是 PHP 7.0 起从源码里物理删除了整个 ext/mysql。它连编译选项都没留,php -m | grep mysql 永远不会输出这一行。别试 extension=mysql,这行在 php.ini 里只会触发警告甚至被忽略。
mysqli_connect() 和 new PDO() 的字符集必须显式设为 utf8mb4
老代码靠 mysql_query("SET NAMES utf8") 撑过 PHP 5,迁移到 mysqli/PDO 后仍乱码,大概率卡在这儿:
-
mysqli_connect()成功后,必须立刻调用mysqli_set_charset($conn, 'utf8mb4');只设 DSN 或只改 php.ini 的default_charset不起作用 - PDO 连接时 DSN 必须带
charset=utf8mb4,例如mysql:host=localhost;dbname=test;charset=utf8mb4,且建议加上PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4" - MySQL 服务端的
character_set_server、库和表的COLLATE也得是utf8mb4_unicode_ci,否则 emoji 和部分汉字存不进去
预处理语句不是“可选优化”,而是防 SQL 注入的唯一可靠路径
用 intval() 或 addslashes() 过滤用户输入,挡不住类型绕过、十六进制编码、逻辑注入等变种。现代写法只认预处理:
- mysqli:用
$stmt = mysqli_prepare($conn, "SELECT * FROM user WHERE id = ?"),再mysqli_stmt_bind_param($stmt, "i", $id) - PDO:用
$stmt = $pdo->prepare("SELECT * FROM user WHERE name = :name"),再$stmt->execute(['name' => $_GET['name']]) - 别再拼字符串:
"WHERE id = " . $_GET['id']在 PHP 7+ 环境下等于主动敞开 SQL 注入大门
mysqli 和 PDO 不是“随便选一个”,迁移成本和长期维护差别很大
如果你只是把 mysql_query() 换成 mysqli_query(),但没调整参数顺序(mysqli 第一个参数是连接资源)、没处理返回值差异(mysqli_query 返回 mysqli_result 或布尔值)、没加错误检查,那只是把报错从 mysql_connect() 推迟到查询执行时。
更关键的是:mysqli 是 MySQL 专用,PDO 是数据库抽象层。如果项目未来可能换 PostgreSQL 或 SQLite,PDO 的 DSN 切换成本几乎为零;而 mysqli 代码得重写全部查询逻辑。另外,PDO 支持命名参数、异常模式(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),错误定位比 mysqli 的手动 mysqli_error() 直观得多。
真正容易被忽略的,是表结构和连接层字符集的同步——哪怕 PHP 和 MySQL 都写了 utf8mb4,只要其中一环是 utf8(3字节版),中文或 emoji 就会变成问号或截断,而且这种问题在线上压测时才暴露,本地开发常看不出来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











