PHP 的 PDO 和 mysqli 有什么区别?该怎么选

阿乐
阿乐 星耀SVIP管理员 黑卡会员
发布于 2026-09-13 13:01 ·2 浏览 ·0 回复

**结论:新项目一律用 PDO;只有当你明确需要 MySQL 独有功能(异步查询、多语句、LOAD DATA LOCAL)时才用 mysqli,纯 MySQL 的老项目也没必要主动迁移。**

本质差别:一个是抽象层,一个是专用驱动

PDO(PHP Data Objects)是数据库访问抽象层,同一套 API 能接 MySQL、PostgreSQL、SQLite、SQL Server 等十余种数据库;mysqli 是 MySQL 专用扩展,只服务于 MySQL。这个定位差异决定了后面几乎所有的取舍。

结论:PDO 换来的是数据库可替换性,mysqli 换来的是 MySQL 特性覆盖率,两者不可兼得。

需要注意 mysqli 有面向对象和过程式两套 API(`$mysqli->query()` 与 `mysqli_query($link, ...)`),过程式写法是历史包袱,新代码不要用。PDO 只有面向对象一套。

功能与写法上的具体差异

结论:日常增删改查两者完全等价,差异集中在参数绑定和边缘特性上。

- 占位符:PDO 支持命名参数 `:id` 和位置参数 `?`,mysqli 只支持 `?`。参数一多,命名参数的可读性优势非常明显。
- 预处理默认行为:mysqli 默认走服务端真预处理;PDO 的 `PDO::ATTR_EMULATE_PREPARES` 默认为 `true`(客户端模拟拼接),这是最容易踩的坑,下面单独说。
- MySQL 专有特性:mysqli 支持异步查询、多语句执行、`LOAD DATA LOCAL INFILE`、`get_result()` 直接拿结果集,PDO 对部分特性支持较弱或没有。
- 异常:PDO 可通过 `PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION` 统一抛异常;mysqli 需要手动 `mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT)` 才有类似体验。

性能:别再拿这个当选型理由

结论:在 PHP 7.4 / 8.x 上,PDO 与 mysqli 的性能差异通常在 5% 以内,不足以影响选型。

两者底层都走 mysqlnd(PHP 官方 MySQL 原生驱动),预处理、结果集解析都在同一层实现。网上流传的「mysqli 快 2 倍」多是十几年前 libmysqlclient 时代的旧测试,或者没对齐预处理模式。真要优化数据库性能,索引、查询条数、连接复用(`PDO::ATTR_PERSISTENT` 要谨慎使用)的收益远大于换扩展。

PDO 的两个必设项和一个坑

结论:PDO 初始化时至少要设三个参数,其中关闭模拟预处理是最容易被忽略的。

$pdo = new PDO('mysql:host=127.0.0.1;dbname=app;charset=utf8mb4', $user, $pass, [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION, // 出错抛异常,而不是静默返回 false
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,       // 默认关联数组,省掉 fetchAll 参数
    PDO::ATTR_EMULATE_PREPARES   => false,                  // 走服务端真预处理
]);

- 必须写 `charset=utf8mb4`:DSN 里带 charset 才会正确设置连接字符集,也能避免宽字节注入的经典问题。mysqli 对应的是连接后调用 `$mysqli->set_charset('utf8mb4')`。
- 模拟预处理的风险:`EMULATE_PREPARES = true` 时占位符由 PDO 在客户端拼装。绝大多数场景仍然安全,但 `LIMIT ?` 绑定字符串时会出问题,且它是「看起来像预处理、实际是拼接」,容易被误判。
- mysqli 的等价初始化

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli('127.0.0.1', $user, $pass, 'app');
$mysqli->set_charset('utf8mb4');

怎么选:三条判断标准

结论:按「是否只用 MySQL / 是否需要专有特性 / 是否可能换库」三个问题决策,答案基本就确定了。

1. 只用 MySQL 且需要异步查询、多语句、`LOAD DATA LOCAL` —— 选 mysqli。
2. 只用 MySQL 但只需要常规 CRUD —— 仍然推荐 PDO,因为代码更干净、迁移成本更低。
3. 现在或未来可能上 PostgreSQL、SQLite —— 必须 PDO,换库时主要改 DSN 和少量方言 SQL,数据层结构基本不动。

补充一点:如果你在开发的是要给别人部署的 PHP 系统,PDO 的兼容面更广。比如 Clara BBS 这类无框架轻量论坛,环境要求是 PHP 7.4-8.5 + MySQL 5.7+、不需要 Composer,PDO 和 mysqli 都随 PHP 默认提供,但 PDO 在支持多数据库上更从容,也更符合「上传即用」的部署思路。

迁移与共存

结论:从 mysqli 迁到 PDO 的成本主要在数据访问层,不要一次性全量重写。

建议做法是新功能直接用 PDO,老代码按模块逐个替换:先把 `mysqli_query` + `mysqli_fetch_assoc` 的直连查询换成 PDO 预处理语句,再处理事务(PDO 的 `beginTransaction / commit / rollBack` 比 mysqli 手工开关自动提交更直观)。迁移过程中注意三件事:把 `utf8mb4` 补进 DSN、把错误模式改成异常、把 `num_rows` 这类 MySQL 特有判断换成 `fetchColumn()` 或计数查询。

一句话收尾:默认选 PDO,把三个初始化参数设对,别关着模拟预处理还自称用了预处理;只有 MySQL 专有特性挡路时,才回头用 mysqli。

本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-301.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
阿乐

全部回复 0

还没有回复,来抢沙发~