Eloquent 不处理重音敏感,由数据库 COLLATION 决定;PHP 层可用 Normalizer::normalize() 归一化,但应存为独立索引字段,不可在访问器/修改器中处理,查询时可显式用 COLLATE 或 whereRaw。

Eloquent 本身不处理重音敏感(accent sensitivity),数据库层面才决定是否区分 é 和 e;PHP 层唯一可控点是手动 normalize 字符串,或在查询时用 COLLATE 显式指定排序规则。
MySQL / PostgreSQL 的重音敏感由字符集和排序规则(COLLATION)决定
不是 Laravel 或 PHP 的责任。例如:
-
utf8mb4_unicode_ci不区分重音(café=cafe) -
utf8mb4_0900_as_cs(MySQL 8.0+)区分重音且大小写敏感 - PostgreSQL 默认
en_US.UTF-8排序规则通常不区分重音,需用UNACCENT()函数或citext扩展
如果你在 where('name', 'café') 中没匹配到数据,先检查表字段的 COLLATION,而不是改模型代码。
PHP 层做重音归一化:用 Normalizer::normalize() 去除变音符号
适用于搜索前标准化输入,或生成“无重音”索引字段(如 name_normalized):
立即学习“PHP免费学习笔记(深入)”;
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
// 示例:将 'café' → 'cafe'
$name = 'café';
$normalized = Normalizer::normalize($name, Normalizer::FORM_D);
$asciiOnly = preg_replace('/\p{Mn}/u', '', $normalized); // 移除组合标记
// $asciiOnly === 'cafe'
注意:
- 必须启用
intl扩展,否则Normalizer不可用 - 别在访问器里自动归一化原始字段(如
getNameAttribute),会破坏原始数据语义 - 若用于搜索,建议把归一化结果存入单独字段 + 添加索引,避免每次
WHERE都调用 PHP 函数
在 Eloquent 查询中强制重音敏感匹配
不能靠模型属性控制,但可在查询时显式加 COLLATE:
User::whereRaw("name COLLATE utf8mb4_0900_as_cs = ?", ['café'])->first();
// 或用 DB::raw() 包裹字段
User::whereRaw("BINARY name = ?", ['café'])->first(); // MySQL 简单二进制比较(不推荐用于多字节)
常见陷阱:
-
where('name', 'café')完全依赖字段默认COLLATION,无法动态切换 -
LIKE查询默认也受COLLATION影响,COLLATE必须写在字段侧,如name COLLATE ... LIKE ? - Laravel 的
when()或作用域里拼whereRaw时,记得转义参数,别直接插值
为什么不要在 Accessor/Modifier 里处理重音逻辑
因为这混淆了「存储表示」和「显示/查询意图」:
- 访问器(
getNameAttribute)只应做格式化(如首字母大写),不该改变语义等价性 - 修改器(
setNameAttribute)若自动去重音,会导致原始数据丢失(比如用户真名叫 «José»,你存成 «Jose» 就错了) - 真正需要的是:入库时保留原样,查时按需归一化 —— 这属于查询构建逻辑,不是属性行为
最易被忽略的一点:即使你在 PHP 层做了完美归一化,如果数据库字段没建索引、或索引基于原始值,WHERE name_normalized = 'cafe' 仍可能慢。归一化字段务必单独建索引。


















