优先用 mbstring,因其容错性强、支持 //IGNORE 和 //TRANSLIT 修饰符,且现代 PHP 环境默认启用;iconv 虽轻量但对非法字符敏感,稳定性差,不推荐为微小性能优势妥协。

mbstring 和 iconv 都能转编码,该选哪个?
优先用 mbstring,前提是 PHP 编译时启用了 mbstring 扩展(现代环境基本默认开启)。iconv 虽然轻量,但对非法字节容忍度低,容易抛出 Notice: iconv(): Detected an illegal character;而 mb_convert_encoding() 支持 //IGNORE 和 //TRANSLIT 修饰符,容错更强,也更贴近实际业务中“尽力转、不崩”的需求。
常见误区:以为 iconv('GBK', 'UTF-8', $str) 总比 mb_convert_encoding($str, 'UTF-8', 'GBK') 快——实测在小文本下差异可忽略,大文本且确定输入绝对合法时 iconv 略快,但稳定性代价太高,不推荐为这点性能妥协。
mb_convert_encoding() 的三个参数怎么填才不出错?
调用格式是 mb_convert_encoding($str, $to_encoding, $from_encoding)。关键点在于第三个参数(源编码)不能乱猜,否则结果不可控:
- 若来源是 HTTP POST 表单或 URL 参数,优先看
$_SERVER['HTTP_CONTENT_TYPE']或mb_http_input()推断,而不是硬写'GBK' - 若读取本地文件,用
mb_detect_encoding($content, ['UTF-8', 'GB2312', 'GBK', 'BIG5'], true)检测,但注意:该函数不保证 100% 准确,尤其对纯英文或短文本易误判,建议配合 BOM 判断(hexdec(bin2hex(substr($content, 0, 3))) === 0xefbbbf) - 如果明确知道来源是 Windows 记事本保存的中文文件,
$from_encoding写'CP936'比'GBK'更准确(PHP 中二者常等价,但 CP936 是微软标准名)
遇到乱码时,先检查 mbstring.func_overload 是否干扰了 strlen 等函数
如果开启了 mbstring.func_overload(如值为 7),会导致 strlen()、substr()、strpos() 等函数自动按字符而非字节操作——这在处理 UTF-8 字符串时看似友好,但极易引发兼容性问题:
立即学习“PHP免费学习笔记(深入)”;
- JSON 解析失败(
json_encode()内部依赖字节长度) - 数据库字段截断异常(PDO/MySQLi 绑定参数前被
substr()错误截断) - 第三方库崩溃(比如某些老版本的 cURL 封装会传入字节偏移,却被覆盖成字符偏移)
建议:关闭 mbstring.func_overload(设为 0),所有多字节操作显式调用 mb_strlen()、mb_substr() 等,代码意图清晰,后续维护和迁移成本更低。
iconv 不支持 //IGNORE?其实可以,但写法很隐蔽
iconv() 默认不接受 //IGNORE,但加上 //TRANSLIT 后就能间接实现跳过非法字符:
iconv('GBK', 'UTF-8//IGNORE', $str) ❌ 报错
iconv('GBK', 'UTF-8//TRANSLIT', $str) ✅ 可用,非法字节会被静默丢弃
iconv('GBK', 'UTF-8//TRANSLIT//IGNORE', $str) ✅ 更稳妥(部分系统支持双修饰符)
不过要注意://TRANSLIT 在某些环境下会把无法转换的字符替换成近似 ASCII 字符(如 “é” → “e”),如果业务要求严格保留原字符形态(或直接丢弃),还是回到 mb_convert_encoding($str, 'UTF-8', 'GBK//IGNORE') 更可控。
真正麻烦的不是函数选哪个,而是同一份数据在不同环节可能混着多种编码:数据库连接层用 SET NAMES utf8mb4,但某张旧表字段其实是 GBK;前端











