PDO读取ENUM字段始终返回字符串值(如"active"),而非序号1,与fetch模式和ATTR_STRINGIFY_FETCHES配置无关;判断时须用字符串比较,需序号则SQL中显式CAST。

读取 ENUM 字段时返回字符串而非整数
PHP 的 PDO 默认将 MySQL ENUM 字段按其定义的字符串值返回,不是底层存储的序号(1-based)。哪怕你在 SQL 里写 SELECT my_enum+0 FROM table 强制转为数字,PDO 仍会按字段元数据类型解析为字符串——除非显式用 CAST 或 CONVERT 干预。
常见错误现象:代码里写 if ($row['status'] === 1) 判断,但实际拿到的是 "active",永远不成立。
- 确认字段真实值用
var_dump($row['status']),别依赖数据库客户端显示的“看起来像数字” - 如需序号,SQL 中必须显式转换:
SELECT CAST(status AS UNSIGNED) as status_num FROM table - 避免在 PHP 层用
(int)$row['status']转换——空字符串、非法值会变 0,掩盖逻辑错误
使用 PDO::FETCH_NUM 或 PDO::FETCH_BOTH 时 ENUM 值仍为字符串
ENUM 的行为与 fetch 模式无关。无论你设 PDO::FETCH_ASSOC、PDO::FETCH_NUM 还是 PDO::FETCH_BOTH,只要字段类型是 ENUM,PDO 就按字符串返回。这不是配置问题,是 MySQL 协议层和 PDO 驱动对 ENUM 类型的固定映射方式。
性能影响很小,但容易误判类型。例如 json_encode() 后字段还是字符串,不会自动变成数字。
立即学习“PHP免费学习笔记(深入)”;
- 不要在
setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false)上浪费时间——它只影响TINYINT(1)这类布尔模拟字段,对ENUM无效 - 若业务强依赖序号,建议在建表时改用
TINYINT+ 注释说明取值含义,更可控
预处理语句中绑定 ENUM 字段值要加引号
向 ENUM 字段插入或 WHERE 匹配时,值必须是合法枚举项的字符串字面量。用预处理语句传参时,PDO 不会自动加引号,但 MySQL 服务端要求字符串值必须带单引号,否则报错 Unknown column 'active' in 'where clause'(被当成列名)。
正确做法是让 PDO 自动处理:参数用 bindValue() 或 execute([$value]),且确保 $value 是字符串类型(如 "active"),PDO 会按需加引号并转义。
- 错误写法:
$stmt->execute([1])—— 数字 1 不是合法枚举值,MySQL 直接拒绝 - 错误写法:
$stmt->execute(['"active"'])—— 多余引号导致传入的是"active"(含双引号的字符串) - 安全写法:
$stmt->bindValue(':status', 'active', PDO::PARAM_STR)
MySQL 8.0+ 的严格模式对 ENUM 插入更敏感
开启 STRICT_TRANS_TABLES 或 STRICT_ALL_TABLES 后,向 ENUM 字段插入非法值(包括空字符串、NULL 但字段非空)会直接报错 Incorrect integer value 或 Data truncated for column,而不是静默转成默认值或空。
这会让旧代码突然崩掉,尤其当测试库没开严格模式而生产开了。
- 检查当前模式:
SELECT @@sql_mode,确认是否含STRICT_* - 开发环境务必和生产一致;CI 流程中加一条
mysql -e "SELECT @@sql_mode"校验 - INSERT 前用
IN子查询校验值合法性:WHERE ? IN (SELECT 'active','inactive'),比靠异常更早暴露问题



















