PHP MySQL 简介
Three ways to reach MySQL: the removed mysql extension, mysqli and PDO.
Three options
| Extension | Status | Multi-database | Named params |
|---|---|---|---|
| mysql | PHP 7.0 已移除 | 否 | 否 |
| mysqli | 内置 | 否(仅 MySQL) | 否 |
| PDO | 内置 | 是(12 种驱动) | 是 |
mysql_* functions were removed in PHP 7. Countless old tutorials still use them — copying them fails immediately.
PDO vs mysqli
- Choose PDO —— driver portability, named placeholders, uniform exceptions
- Choose mysqli —— MySQL-only with its specific features (async queries, multi_query)
- Either works —— most code only uses prepare/execute/fetch
What a DSN is
PDO describes a connection as driver:key=value;key=value. **Always include charset=utf8mb4** or Chinese text may corrupt.
<?php
$dsn = "mysql:host=127.0.0.1;port=3306;dbname=demo;charset=utf8mb4";
foreach (explode(";", substr($dsn, 6)) as $pair) {
[$k, $v] = explode("=", $pair, 2);
echo str_pad($k, 8) . "=> " . $v . "\n";
}host => 127.0.0.1
port => 3306
dbname => demo
charset => utf8mb4utf8mb4 differs from utf8: MySQL's utf8 is 3-byte only and cannot store emoji. Use utf8mb4 for full Unicode.
Three must-set attributes
| Attribute | Value | Why |
|---|---|---|
| ATTR_ERRMODE | ERRMODE_EXCEPTION | 出错抛异常,不会静默返回 false |
| ATTR_DEFAULT_FETCH_MODE | FETCH_ASSOC | 默认关联数组,不用每次传参数 |
| ATTR_EMULATE_PREPARES | false | 用真正的服务端预处理,类型更准 |
ERRMODE_SILENT, a failed query just returns false. Forget to check and the page looks fine while SQL fails — the hardest bug class to trace.Prerequisites
# 检查扩展是否启用
php -m | grep -E "pdo|pdo_mysql"
# 没有的话装(Debian / Ubuntu)
# apt install php-mysql
# 检查 MySQL 是否在跑
# mysqladmin -u root -p statuspdo and pdo_mysql are separate extensions. With only the former, new PDO("mysql:...") reports could not find driver.
三条路
| 扩展 | 状态 | 多数据库 | 命名占位符 |
|---|---|---|---|
| mysql | PHP 7.0 已移除 | 否 | 否 |
| mysqli | 内置 | 否(仅 MySQL) | 否 |
| PDO | 内置 | 是(12 种驱动) | 是 |
mysql_* 系列函数(mysql_query、mysql_connect)在 PHP 7 被彻底删除。网上大量老教程还在用,照抄会直接报错。
PDO 与 mysqli 怎么选
- 选 PDO —— 需要换数据库、喜欢命名占位符、想要统一的异常处理
- 选 mysqli —— 只用 MySQL 且需要它的特有功能(异步查询、
mysqli_multi_query) - 都行 —— 大多数业务代码只用
prepare/execute/fetch,两者没差别
DSN 是什么
PDO 用一个字符串描述连接:驱动:键=值;键=值。**charset=utf8mb4 必须写**,否则中文可能乱码。
<?php
$dsn = "mysql:host=127.0.0.1;port=3306;dbname=demo;charset=utf8mb4";
foreach (explode(";", substr($dsn, 6)) as $pair) {
[$k, $v] = explode("=", $pair, 2);
echo str_pad($k, 8) . "=> " . $v . "\n";
}host => 127.0.0.1
port => 3306
dbname => demo
charset => utf8mb4utf8mb4 和 utf8 不是一回事:MySQL 的 utf8 只支持 3 字节字符,存不了 emoji。要存完整的 Unicode 必须用 utf8mb4。
三个必设属性
| 属性 | 值 | 原因 |
|---|---|---|
| ATTR_ERRMODE | ERRMODE_EXCEPTION | 出错抛异常,不会静默返回 false |
| ATTR_DEFAULT_FETCH_MODE | FETCH_ASSOC | 默认关联数组,不用每次传参数 |
| ATTR_EMULATE_PREPARES | false | 用真正的服务端预处理,类型更准 |
ERRMODE_SILENT 下,$pdo->query() 出错只返回 false,不会中断。忘了检查返回值,SQL 挂了页面还是「正常」的——这是最难查的一类 bug。准备工作
# 检查扩展是否启用
php -m | grep -E "pdo|pdo_mysql"
# 没有的话装(Debian / Ubuntu)
# apt install php-mysql
# 检查 MySQL 是否在跑
# mysqladmin -u root -p statuspdo 和 pdo_mysql 是两个不同的扩展,只有前者没有后者时,new PDO("mysql:...") 会报 could not find driver。