字段映射是模型读写时自动桥接表单名与数据库字段名的关键机制,不配则create()丢数据,配错则find()返回无目标键;tp6中通过protected $map实现双向转换,需配合read_data_map=>true或parsefieldsmap()才生效。

字段映射不是“让数据库字段换个名字显示”,而是让模型在读写时自动桥接表单名 ↔ 数据库字段名——不配,create() 就会丢数据;配错,find() 返回的数组里根本没你想要的键。
用 $map 实现表单字段到数据库字段的双向转换
这是最轻量、最直接的字段别名方式,适用于不想暴露真实字段名(比如 username 映射成 name)或前端传参习惯与数据库命名不一致的场景。
-
$map只影响create()、save()等写入操作,以及parseFieldsMap()手动调用后的读取结果;它不会改变模型内部原始数据结构 - 必须配合
READ_DATA_MAP => true配置,或显式调用$model->parseFieldsMap($data),否则find()返回的仍是原始字段(如username),不是映射名(如name) - 映射关系是单向的:表单提交
name=xxx→ 自动转成username=xxx入库;但数据库查出username=yyy不会自动变成name=yyy,除非开启READ_DATA_MAP - TP6 中该属性已改为
$map(非 TP5 的$_map),定义在模型类中:protected $map = [ 'name' => 'username', 'mail' => 'email', 'status' => 'user_status' ];
getAttr() 和 setAttr() 用于字段值的动态转换
当你要的不是“换个字段名”,而是“对字段值做处理”(比如 ENUM 转中文、时间戳转日期字符串、敏感字段脱敏),就得用访问器(getAttr)和修改器(setAttr)。
-
getAttr在读取字段时触发,例如$user->name或$user->getData('name');注意:它只对模型属性名生效,不是数据库字段名。若数据库字段是user_name,而你想给它加获取器,函数名得是getUserNameAttr() -
setAttr在赋值时触发,例如$user->name = 'xxx';它能拦截并改写写入值,适合做格式标准化(如把手机号统一补 86)、ENUM 写入校验等 - 二者不强制成对出现。比如你只定义了
getStatusTextAttr()用于读取展示,但写入仍走原始字段status,那就不用写setStatusAttr() - 避免在
getAttr里做耗时操作(如 DB 查询),它会在每次访问该属性时执行
字段名自动下划线 ↔ 驼峰转换常被误当作“映射”
很多开发者以为 TP 默认就把 last_login_time 自动转成 lastLoginTime 属性,于是直接在代码里写 $user->lastLoginTime ——这其实依赖的是 TP 的字段自动转换机制,不是映射,且极易失效。
- 该行为由配置项
fields_strict和模型属性$convertName控制;一旦关闭或环境不一致(如 CLI 下运行),$user->lastLoginTime就会返回null - 调试时发现
$user->getData('last_login_time')有值,但$user->lastLoginTime没值?大概率是字段转换没生效,而不是映射没配 - 真正可靠的写法是:统一用小写下划线字段名开发,并在模型中显式声明
protected $convertName = true;(TP6);不要依赖隐式转换去“模拟映射” - 如果数据库字段本身含大写字母(如
APIKey),TP 默认转换会失败,此时必须用getAttr()手动接管
关联模型字段映射容易漏掉,导致输出结构混乱
主模型配了 $map 或 getAttr(),但 with('profile') 加载的关联模型没配,结果主模型返回 name,关联模型却返回 username ——前端解析时字段风格不统一,容易出错。
-
with()加载的关联模型各自走自己的toArray()和字段转换逻辑,不会继承主模型的映射规则 - 若所有模型都需统一字段风格,必须让它们继承同一个基类,且基类中统一定义
$map、getAttr()或重写toArray() - 第三方模型无法修改时,可用
hidden+append补字段:隐藏原始字段,再用访问器生成别名字段;但别删原始字段,否则 ORM 内部关联逻辑可能异常 - 测试时一定要看完整
toJson()输出,不能只验主模型一层
字段映射真正的复杂点不在语法,而在“作用域边界”:它只在特定方法(create、parseFieldsMap)、特定配置(READ_DATA_MAP)、特定生命周期(getAttr 触发时机)下生效。漏掉任一环,就变成“配了但没用”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











