需在模型文件首行添加declare(strict_types=1);声明,且不可有空白行或bom头,否则strict_types=1无法生效导致类型不匹配时静默存入0或空字符串。

在ThinkPHP 8.0中启用strict_types=1后,模型属性赋值若不匹配字段真实类型,会导致create()静默存入0或空字符串,而非抛出TypeError——这不是框架bug,是PHP类型系统与TP8模型层协作规则未对齐所致。
开启严格模式并确保模型文件生效
打开你的模型文件(如app/model/User.php),在文件最顶部添加声明行,【必须是第一行且不能有空白行或BOM头】:
保存后清空runtime/cache目录,否则旧opcode可能缓存未生效的类型检查逻辑。
验证是否生效:在该模型中故意写一个带类型提示但传错参数的方法,如public function test(int $id) { return $id; },然后调用test('abc')——若报Fatal error: Uncaught TypeError则成功;若无报错,说明declare未起作用,大概率是文件开头有不可见字符或被其他自动加载机制绕过。
字段类型转换配置必须手动写,且仅对查询结果生效
方法一:在模型类中定义$type数组
protected $type = [ 'status' => 'integer', 'price' => 'float', 'is_vip' => 'boolean', 'created_at' => 'datetime' ];
注意:键名必须与数据库字段名完全一致(含下划线、大小写),写成'statusId'或'Status'均无效;值必须用全小写英文标识符,'int'或'BOOL'会被忽略。
方法二:运行时动态设置
$user = new User();
$user->setType(['score' => 'float'])->where('id', 1)->find();
该方式只影响本次查询链,不改变模型类定义,适合多租户场景下按表结构动态适配类型。
写入时的类型处理必须手动干预
第一步:确认数据库字段类型与业务预期一致
例如status字段在MySQL中是TINYINT(1),那就不能期望模型自动把字符串'on'转成1——TP8不会做这种语义映射,只做基础类型强制转换。
第二步:在赋值前显式转换
$data = ['status' => (int) $request->post('status'), 'price' => (float) $request->post('price')];
User::create($data);
第三步:或重写模型的setAttr方法实现字段级强约束
public function setStatusAttr($value)
{
if (!is_int($value) && !is_string($value)) {
throw new InvalidArgumentException('status must be int or numeric string');
}
return (int) $value;
}
这一步操作起来很简单,直接把类型校验逻辑塞进setAttr里就行,但要注意:它只在模型实例赋值时触发(如$user->status = '1'),不覆盖create()的批量赋值路径。
JSON字段必须双保险:$json声明 + 写入前合法性校验
在模型中声明JSON字段:
protected $json = ['extra', 'settings'];
写入前必须校验JSON合法性,否则json_encode()遇到资源或循环引用会直接崩溃:
$extra = $request->post('extra', []);
if (!is_array($extra) || json_encode($extra, JSON_THROW_ON_ERROR) === false) {
throw new ValidateException('extra must be valid JSON array');
}
User::create(['extra' => $extra]);
【不校验就写入,MySQL可能存入空字符串或截断,且无任何提示】
获取器中禁止返回非声明类型的数据
public function getScoreTextAttr($value, $data)
{
// 错误:返回null,但方法签名无?int声明,strict模式下可能触发弱类型警告
if (empty($data['score'])) {
return null;
}
// 正确:保持类型一致,用0兜底或改方法签名为?string
return (string) $data['score'];
}
获取器本质是普通PHP方法,strict_types=1对其参数和返回值同样生效;若返回类型与调用处期待不符(如模板里直接echo $user->scoreText . '分',而scoreText返回null),PHP 8.0+会在运行时抛出TypeError。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











