$fillable 在 TP6.0.14 中仅在模型属性赋值+save/saveAll 流程中生效,Db 类操作、data() 赋值、字段名不匹配、隐藏字段干扰或非法字段校验均会导致其失效。

$fillable 在 ThinkPHP 6.0.14 中写入失败,不是字段没加进白名单,而是根本没走模型的 save() 或 saveAll() 的属性赋值流程。TP6 的 $fillable 是模型层字段过滤机制,只在「通过模型属性赋值 + 调用模型保存方法」时生效,绕过它就完全失效。
常见导致 $fillable 看似“不生效”的真实原因
直接调用
Db::name('user')->insert()或insertAll()
这类 Db 类操作完全不经过模型,$fillable、$casts、访问器/修改器、自动完成等全部失效。字段是否写入,只取决于你传的数组键名是否真实存在于数据表中。使用
saveAll()但未正确设置allowField()saveAll()默认会校验字段合法性(比insertAll()严格),但如果数据里混入了数据库不存在的字段(如full_name、avatar_url),TP6.0.14 会直接抛出异常或静默跳过整条记录——看起来像$fillable没起作用,其实是字段校验拦截了。模型中定义了
$hidden或未配置$visible,间接影响字段识别
TP6 对字段的读写控制存在链式依赖:若字段被$hidden = ['password']显式隐藏,部分版本下save()批量赋值时可能跳过该字段处理(尤其搭配data()或isUpdate(false)使用时)。$fillable写的是别名或驼峰字段名,但数据库实际是下划线命名
例如数据库字段是user_name,你在$fillable = ['userName']里写了驼峰,TP6 不会自动转换;必须写成'user_name'才匹配。注意:TP6 不支持像 Laravel 那样自动蛇形/驼峰映射$fillable字段。-
使用
data()方法赋值后调用save()$user->data(['user_name' => '张三', 'email' => 'z3@x.com'], true); $user->save();
data()绕过了__set()魔术方法,因此修改器(setUserNameAttr)、类型转换、甚至$fillable校验都不会触发。立即学习“PHP免费学习笔记(深入)”;
如何确认 $fillable 是否真正参与了写入
用以下方式验证是否走对了路径:
-
✅ 正确触发(推荐):
$user = new UserModel(); $user->user_name = '张三'; // 触发 __set → 检查 $fillable $user->email = 'z3@x.com'; $user->save(); // 成功写入,且受 $fillable 控制
-
✅ 批量也有效:
UserModel::create(['user_name' => '李四', 'email' => 'l4@x.com']); // 受 $fillable 控制
-
❌ 错误绕过(
$fillable完全不运行):Db::name('user')->insert(['user_name' => '王五', 'password' => 'xxx']); // 不经模型,无任何过滤
快速排查步骤
- 打印你传入的数据键名:
array_keys($data[0] ?? $data),确认是否含非法字段(如created_at_text、status_label); - 检查模型中
$fillable数组里的字段名,是否与数据库字段逐字一致(区分下划线/驼峰); - 查看是否误用了
Db::insertAll()而非UserModel::saveAll(); - 若用
saveAll(),加上allowField()显式声明白名单更稳妥:(new UserModel())->allowField(['user_name', 'email'])->saveAll($data);
不复杂但容易忽略。



















