Laravel版本升级后模型变化_Laravel模型升级调整汇总【汇总】

3次阅读

laravel 9+ 中模型批量赋值需显式定义 $fillable 或 $guarded(10.x 要求 $guarded = [‘*’]),casts 中 ‘date’ 不再返回 carbon,须改用 ‘datetime’,模型事件应改用 observe() 注册,关系方法需严格匹配框架泛型返回类型。

Laravel版本升级后模型变化_Laravel模型升级调整汇总【汇总】

模型的 $fillable$guarded 在 9.x 后更严格了

升级到 Laravel 9 或更高版本后,如果模型里没显式定义 $fillable$guarded,批量赋值(create()update())会直接抛出 MassAssignmentException,而不是静默忽略——这是默认行为变更,不是你代码写错了。

常见错误现象:本地开发正常,上线后表单提交报错 add() expects parameter 1 to be Array, NULL given 或更直白的 class AppModelsPost contains no Property $fillable(其实是没定义导致拒绝所有字段)。

  • 必须在每个模型里明确声明 $fillable = ['title', 'content']$guarded = [](后者等于全放开,不推荐)
  • Laravel 10 进一步收紧:连 $guarded = [] 都会被视为“未受保护”,需改用 $guarded = ['*'] 才等效于“无保护”(注意是字符串 '*',不是空数组)
  • 别依赖父类或 trait 提供的 $fillable —— PHP 不会自动合并数组属性,子类必须重写或显式继承

casts 中日期类型不再自动转 Carbon 实例(Laravel 9+)

升级后发现 $model->published_at->format('Y-m-d') 报错 “Call to a member function format() on String”,是因为 casts 里写的 'published_at' => 'date' 不再隐式转成 Carbon,只做基础类型转换(string → DateTimeImmutable)。

使用场景:需要链式调用 ->addDays()->diffForHumans() 等方法时,必须显式指定类名。

  • 改成 'published_at' => 'datetime'(返回 Carbon)或 'published_at' => 'immutable_datetime'(返回 CarbonImmutable
  • 若仍用 'date',访问时得手动封装Carbon::parse($model->published_at)
  • 注意迁移兼容性:旧数据如果是 Y-m-d 格式字符串,datetime cast 会尝试补全为当日 00:00:00;date 则保持字符串,不补时间

模型事件监听器注册方式从静态方法改为服务容器绑定(Laravel 9.23+)

以前在模型里写 Static::created(...)boot() 里调 static::updating(...) 还能用,但升级后可能漏触发——因为 Laravel 改用容器解析模型实例时才注册监听器,静态闭包注册被绕过了。

错误现象:本地测试没问题,队列任务或 API 测试中模型事件完全不执行。

  • 统一改用 Observing:在 AppServiceProvider::boot() 里加 AppModelsPost::observe(AppObserversPostObserver::class)
  • Observer 类里方法名必须严格匹配:如 created()updated()deleting()(注意是 deleting,不是 deleted,后者是事后钩子,不支持取消操作)
  • 避免在 Observer 方法里调用 $model->save(),可能引发递归监听或事务异常

关系方法返回类型声明冲突(PHP 8.1+ + Laravel 9+)

启用了 PHP 8.1 的属性类型或返回类型后,模型关系方法如 public function author(): BelongsTo 会和 Laravel 框架内部泛型声明冲突,报错 Declaration of AppModelsPost::author() must be compatible with IlluminatedatabaseEloquentModel::author(): IlluminateDatabaseEloquentRelationsBelongsTo

根本原因是 Laravel 9 的关系方法返回类型是完整命名空间路径,而你写的可能是简写或漏了泛型参数。

  • 正确写法:use IlluminateDatabaseEloquentRelationsBelongsTo; 然后 public function author(): BelongsTo
  • 集合关系必须带泛型:public function comments(): HasMany<comment></comment>Comment 是模型类)
  • 如果用 PHPStan 或 Pest 做类型检查,还要确保 composer.json"laravel/framework": "^9.48" 或更高,低版本泛型支持不全

最常被忽略的是:升级后没跑 php artisan ide-helper:models 更新 PHPDoc,IDE 里依然提示类型错误,但实际运行没问题——这容易让人误判问题根源。

text=ZqhQzanResources