메인 콘텐츠로 건너뛰기

개요

Eloquent 모델은 인스턴스화될 때마다 “부팅 처리(boot)“와 “초기화 처리(initialize)“를 실행합니다. 트레이트에 이러한 메서드를 정의해 두면, 모델이 해당 트레이트를 use 하는 것만으로 자동으로 호출됩니다. 이 메커니즘을 활용하면 모델에 기능을 주입하는 트레이트를 깔끔하게 구현할 수 있습니다. Laravel 프레임워크 자체도 SoftDeletes 등 많은 트레이트에서 이 패턴을 활용하고 있습니다.

boot와 initialize의 차이

bootXxx()initializeXxx()
호출 시점모델 클래스가 최초로 부팅될 때(클래스당 1회)인스턴스가 생성될 때마다
메서드 종류static인스턴스 메서드
용도이벤트 리스너 등록, 글로벌 스코프 추가 등기본값 설정, 프로퍼티 초기화 등

네이밍 규약

bootXxx()

트레이트 이름 앞에 boot 접두어를 붙인 static 메서드를 정의하면, 모델 부팅 시 한 번만 호출됩니다.
namespace App\Models\Concerns;

trait HasSlug
{
    public static function bootHasSlug(): void
    {
        static::creating(function ($model) {
            if (empty($model->slug)) {
                $model->slug = str($model->name)->slug()->toString();
            }
        });
    }
}
모델에서의 사용 예:
use App\Models\Concerns\HasSlug;

class Article extends Model
{
    use HasSlug;
    // bootHasSlug() 는 자동으로 호출된다
}

initializeXxx()

트레이트 이름 앞에 initialize 접두어를 붙인 인스턴스 메서드를 정의하면, 모델을 new 할 때마다 호출됩니다.
namespace App\Models\Concerns;

trait HasDefaultStatus
{
    public function initializeHasDefaultStatus(): void
    {
        $this->attributes['status'] ??= 'draft';
    }
}
$casts 에 동적으로 추가할 때에도 사용할 수 있습니다:
trait HasMetadata
{
    public function initializeHasMetadata(): void
    {
        $this->mergeCasts([
            'metadata' => 'array',
        ]);
    }
}

PHP Attribute를 통한 명시적 지정

Laravel 11부터는 네이밍 규약에 의존하지 않고 PHP Attribute로 메서드를 명시적으로 지정할 수 있습니다.
Attribute대상
#[Boot]클래스 부팅 시 한 번만 실행할 메서드
#[Initialize]인스턴스 생성 시마다 실행할 메서드
use Illuminate\Database\Eloquent\Attributes\Boot;
use Illuminate\Database\Eloquent\Attributes\Initialize;

trait HasAuditLog
{
    #[Boot]
    public static function registerAuditListeners(): void
    {
        static::created(function ($model) {
            AuditLog::record('created', $model);
        });

        static::updated(function ($model) {
            AuditLog::record('updated', $model);
        });
    }

    #[Initialize]
    public function setAuditDefaults(): void
    {
        $this->attributes['audit_enabled'] ??= true;
    }
}
PHP Attribute를 사용하면 메서드 이름이 트레이트 이름에 얽매이지 않기 때문에, 의미 있는 이름을 붙일 수 있습니다. 여러 개의 #[Boot] 메서드나 #[Initialize] 메서드를 같은 트레이트 안에 정의하는 것도 가능합니다.

실전 예제: 패키지 개발에서의 활용

글로벌 스코프의 자동 추가

trait HasTenant
{
    public static function bootHasTenant(): void
    {
        static::addGlobalScope(new TenantScope);
    }
}

기본 캐스트 추가

trait HasJsonSettings
{
    public function initializeHasJsonSettings(): void
    {
        $this->mergeCasts([
            'settings' => 'array',
        ]);
    }
}

Eloquent 이벤트로 자동 처리

trait Archivable
{
    #[Boot]
    public static function bootArchivable(): void
    {
        static::deleting(function ($model) {
            Archive::store($model->toArray());
        });
    }
}

Laravel 프레임워크 내의 예시

Laravel 프레임워크 자체도 많은 트레이트에서 이 패턴을 채택하고 있습니다.
트레이트메서드처리 내용
SoftDeletesbootSoftDeletes()소프트 삭제용 글로벌 스코프 추가
HasFactorybootHasFactory()특별한 처리 없음(범위 외 메커니즘)
HasUlidsbootHasUlids()creating 이벤트에서 ULID를 자동 설정
HasUuidsbootHasUuids()creating 이벤트에서 UUID를 자동 설정
이들을 참고 구현으로 읽어 보면, 패턴에 대한 이해가 더 깊어집니다.

주의 사항

모델 캐시 초기화

boot* 는 클래스마다 한 번만 실행되기 때문에, 테스트 환경에서는 주의가 필요합니다. Model::clearBootedModels() 로 부팅된 캐시를 리셋할 수 있습니다.
// 테스트 종료 후 모델의 부팅 상태를 리셋한다
protected function tearDown(): void
{
    Model::clearBootedModels();
    parent::tearDown();
}

실행 순서

같은 모델에 여러 트레이트가 use 되어 있을 경우, bootXxx() / initializeXxx() 는 PHP의 트레이트 해결 순서(선언 순서)로 호출됩니다. 의존 관계가 있다면 use 순서에 주의하시기 바랍니다.

정리

패턴방법적용 상황
클래스 부팅 시 처리static bootXxx() 또는 #[Boot]이벤트 등록, 글로벌 스코프 추가
인스턴스 초기화initializeXxx() 또는 #[Initialize]기본값, 캐스트 추가
트레이트에 bootXxx() / initializeXxx() 를 구현해 두면, 모델에 기능을 주입하는 일이 use 한 줄로 끝나게 됩니다. 패키지에서 모델에 기능을 추가할 때의 정석 패턴입니다.
마지막 수정일 2026년 7월 13일