最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
为什么 TP6.0 模型修改器不生效:数据类型与赋值时机剖析 源码
时间:2026-07-10 10:10:03 编辑:袖梨 来源:一聚教程网
模型修改器仅在模型的save()、create()、update()等方法中触发,Db::insert()或原生SQL插入时不生效;setFieldAttr签名须为public function setFieldAttr($value, $data = null),且$type转换优先于修改器执行。
模型修改器只在模型的 save()、create()、update() 等方法中触发,直接调用 Db::insert() 或原生 SQL 插入时完全不生效。
修改器只对模型写入方法有效
这是最常被忽略的前提。TP6 的修改器(setFieldAttr)是模型层的逻辑,不是数据库驱动或查询构建器的功能。
- ✅ 生效场景:
UserModel::create(['email' => '[email protected]'])、$user->name = 'x'; $user->save(); - ❌ 不生效场景:
Db::name('user')->insert(['email' => '[email protected]'])、$model->data($data)->isUpdate(false)->save();(绕过模型校验与修改器流程) - ⚠️ 注意:即使用了模型实例,但手动调用
->insert()(如$model->insert($data))也不会触发修改器——因为那是底层 Query 操作,跳过了模型的save()生命周期
setFieldAttr 函数签名与参数陷阱
修改器函数必须严格匹配签名 public function setFieldAttr($value, $data = null),否则框架无法识别或调用失败。
-
$value是你传入的原始值(比如'[email protected]'),不是数据库字段当前值 -
$data是当前要写入的完整数据数组(仅在save()时存在;create()中可能为空) - 常见错误:漏掉第二个参数声明(
function setEmailAttr($value)),导致 PHP 7+ 严格模式下报Declaration must be compatible警告,修改器静默失效 - 示例正确写法:
public function setEmailAttr($value, $data = null){ return strtolower($value);}
类型转换($type)与修改器的执行顺序冲突
如果模型同时定义了 $type 和 setFieldAttr,TP6 会先做类型转换,再进修改器——这意味着你拿到的 $value 可能已是转换后的类型,而非原始字符串。
- 例如:
protected $type = ['price' => 'integer'];
+public function setPriceAttr($value) { return $value * 100; }→ 传入'19.99'会被先转成整型19,再进修改器变成1900,而非预期的1999 - 解决办法:要么移除
$type,改由修改器统一处理(推荐);要么在修改器里手动还原原始输入(需配合getData()或前置缓存) - 验证方式:在修改器内
dump($value); die;,确认它是不是你认为的“原始值”
replace(true) 和修改器毫无关系
有用户误以为 replace(true) 是开启修改器的开关,其实它只影响 SQL 类型(REPLACE INTO vs INSERT INTO),和模型逻辑完全解耦。
-
$model->replace(true)->save($data)会触发修改器(因为仍是save()) -
$model->replace(true)->insert($data)不会触发修改器(因为走的是底层insert()) - 源码佐证:在
think/db/Mysql::insert()中,$replace参数只用于拼 SQL 字符串,不参与模型事件分发
真正决定修改器是否运行的,是「是否经过模型的 save() 流程」,而不是某个布尔配置项或 SQL 关键字。只要绕开模型写入入口,哪怕写满 10 个 setXxxAttr,也只会安静地躺在那里,一动不动。
相关文章
- 猫王小黄鸭 07-21
- 日落海滩时尚人像 07-21
- iOS哔咔网页版入口-哔咔漫画iOS网页版入口 07-21
- 高级定制时装风暴巨片 07-21
- 卧室抓拍人像生活方式 07-21
- 影棚电影级时尚肖像 07-21