跳转到主要内容

什么是模型事件

Eloquent 模型会在生命周期的各时点自动触发事件。通过挂钩这些事件,可以在模型保存、删除等操作的前后插入自定义处理。 Eloquent 触发的事件如下。
事件触发时机
retrieved从 DB 取回模型时
creating保存新模型前
created保存新模型后
updating更新已有模型前
updated更新已有模型后
saving新增或更新保存前
saved新增或更新保存后
deleting删除模型前
deleted删除模型后
trashed软删除后
forceDeleting物理删除前
forceDeleted物理删除后
restoring恢复软删除前
restored恢复软删除后
replicating调用 replicate()
-ing 结尾的事件在变更持久化到 DB 之前触发,以 -ed 结尾的则在之后触发。
批量更新与批量删除(如 User::where(...)->update(...))不会触发 savingsavedupdatingupdateddeletingdeleted 事件,因为模型并未真正被实例化。

用闭包注册事件监听

若希望简单处理事件,可以在模型的 booted 方法内注册闭包。
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected static function booted(): void
    {
        static::created(function (User $user) {
            // 用户创建后执行的处理
        });

        static::deleting(function (User $user) {
            // 用户删除前执行的处理
        });
    }
}
若要将处理放入队列异步执行,使用 queueable 辅助函数。
use function Illuminate\Events\queueable;

static::created(queueable(function (User $user) {
    // 会通过队列异步执行
}));

$dispatchesEvents 属性

如果想与 Laravel 的事件系统联动,可以通过 $dispatchesEvents 属性将模型事件映射到自定义事件类。
<?php

namespace App\Models;

use App\Events\UserDeleted;
use App\Events\UserSaved;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    /**
     * 模型事件与事件类的映射
     *
     * @var array<string, string>
     */
    protected $dispatchesEvents = [
        'saved' => UserSaved::class,
        'deleted' => UserDeleted::class,
    ];
}
映射到的事件类会在构造函数中接收模型实例。
<?php

namespace App\Events;

use App\Models\User;

class UserSaved
{
    public function __construct(
        public readonly User $user,
    ) {}
}

创建 Observer 类

若要处理同一模型的多个事件,将闭包排成一列不如整合到 Observer 类中更加清爽。
1

用 Artisan 命令生成类

使用 make:observer 命令生成模板。通过 --model 选项指定模型时,会自动附上相应方法。
php artisan make:observer UserObserver --model=User
将生成 app/Observers/UserObserver.php
2

实现各事件方法

方法名对应事件名。参数中会传入模型实例。
<?php

namespace App\Observers;

use App\Models\User;

class UserObserver
{
    public function created(User $user): void
    {
        // 用户创建后的处理
    }

    public function updated(User $user): void
    {
        // 用户更新后的处理
    }

    public function deleted(User $user): void
    {
        // 用户删除后的处理
    }

    public function restored(User $user): void
    {
        // 软删除恢复后的处理
    }

    public function forceDeleted(User $user): void
    {
        // 物理删除后的处理
    }
}
3

将 Observer 注册到 Model

注册方式有 2 种。Laravel 13 推荐使用 #[ObservedBy] 属性。方式 1:#[ObservedBy] 属性(推荐)只需在模型类上添加属性即可完成注册,无需修改 AppServiceProvider
<?php

namespace App\Models;

use App\Observers\UserObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Foundation\Auth\User as Authenticatable;

#[ObservedBy(UserObserver::class)]
class User extends Authenticatable
{
    //
}
要注册多个 Observer 时,可重复使用属性或以数组形式传入。
#[ObservedBy(UserObserver::class)]
#[ObservedBy(AuditObserver::class)]
class User extends Authenticatable
{
    //
}
方式 2:在 AppServiceProvider 中注册AppServiceProviderboot 方法中调用 observe
<?php

namespace App\Providers;

use App\Models\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        User::observe(UserObserver::class);
    }
}
#[ObservedBy] 属性位于 Illuminate\Database\Eloquent\Attributes 命名空间。它使用 PHP 8.0 以后的原生语法,在 Laravel 13 中被积极采用。

数据库事务中的 Observer

若模型是在事务内创建或更新,有时你希望 Observer 在事务提交之后执行。实现 ShouldHandleEventsAfterCommit 接口即可获得该行为。
<?php

namespace App\Observers;

use App\Models\User;
use Illuminate\Contracts\Events\ShouldHandleEventsAfterCommit;

class UserObserver implements ShouldHandleEventsAfterCommit
{
    public function created(User $user): void
    {
        // 事务提交后执行
    }
}
在事务外部执行时,会像往常一样立即执行。

暂时禁用事件

使用 withoutEvents 在特定处理中停止事件

在传给 User::withoutEvents() 的闭包内,任何模型事件都不会触发。
use App\Models\User;

$user = User::withoutEvents(function () {
    User::findOrFail(1)->delete();

    return User::find(2);
});

使用 saveQuietly 停止保存事件

想不触发事件地保存模型时使用 saveQuietly
$user = User::findOrFail(1);

$user->name = 'Victoria Faith';

$user->saveQuietly();
对应的方法在删除、恢复、复制中也提供。
$user->deleteQuietly();
$user->restoreQuietly();

实战用例

自动清理缓存

模型更新或删除时,自动清除相关缓存。
<?php

namespace App\Observers;

use App\Models\Post;
use Illuminate\Support\Facades\Cache;

class PostObserver
{
    public function saved(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }

    public function deleted(Post $post): void
    {
        Cache::forget("post:{$post->id}");
        Cache::forget('posts:latest');
    }
}

记录审计日志

自动记录模型的变更历史。使用 getDirty() 可以获取变更前后的值。
<?php

namespace App\Observers;

use App\Models\AuditLog;
use App\Models\User;

class UserObserver
{
    public function updating(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => $user->getDirty(),
            'user_id'    => auth()->id(),
        ]);
    }

    public function deleted(User $user): void
    {
        AuditLog::create([
            'model_type' => User::class,
            'model_id'   => $user->id,
            'changes'    => ['deleted' => true],
            'user_id'    => auth()->id(),
        ]);
    }
}
updating 事件在写入 DB 之前触发,因此 getDirty() 可以取到即将变更的值。如果在 updated 事件之后调用,getDirty() 会为空。

关联模型的自动更新

订单完成时自动更新库存的示例。
<?php

namespace App\Observers;

use App\Models\Order;

class OrderObserver
{
    public function created(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->decrement('stock', $item->quantity);
        }
    }

    public function deleted(Order $order): void
    {
        foreach ($order->items as $item) {
            $item->product->increment('stock', $item->quantity);
        }
    }
}

下一步

进阶:PHP 属性

一起学习包括 #[ObservedBy] 在内的 Laravel 13 PHP 属性。
最后修改于 2026年7月13日