Saltar al contenido principal

Resumen

Cada vez que se instancia un modelo Eloquent se ejecutan dos fases: el “arranque” (boot) y la “inicialización” (initialize). Si defines determinados métodos en un trait, basta con que el modelo lo declare mediante use para que Eloquent los descubra y los invoque automáticamente. Gracias a este mecanismo puedes implementar traits que inyectan funcionalidad en tus modelos de forma limpia. El propio framework Laravel aprovecha este patrón en muchos traits como SoftDeletes, HasUuids o HasUlids.

Diferencia entre boot e initialize

bootXxx()initializeXxx()
Momento de invocaciónLa primera vez que arranca la clase del modelo (una vez por clase)Cada vez que se crea una instancia
Tipo de métodostaticMétodo de instancia
Uso típicoRegistrar listeners de eventos, añadir global scopes, etc.Establecer valores por defecto, inicializar propiedades, etc.

Convenciones de nomenclatura

bootXxx()

Si defines un método static con el prefijo boot seguido del nombre del trait, se invocará una sola vez al arrancar el modelo.
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();
            }
        });
    }
}
Uso desde el modelo:
use App\Models\Concerns\HasSlug;

class Article extends Model
{
    use HasSlug;
    // bootHasSlug() se invoca automáticamente
}

initializeXxx()

Si defines un método de instancia con el prefijo initialize seguido del nombre del trait, se invocará cada vez que se haga new sobre el modelo.
namespace App\Models\Concerns;

trait HasDefaultStatus
{
    public function initializeHasDefaultStatus(): void
    {
        $this->attributes['status'] ??= 'draft';
    }
}
También sirve para añadir dinámicamente entradas a $casts:
trait HasMetadata
{
    public function initializeHasMetadata(): void
    {
        $this->mergeCasts([
            'metadata' => 'array',
        ]);
    }
}

Especificación explícita mediante PHP Attributes

A partir de Laravel 11 puedes indicar los métodos explícitamente con PHP Attributes, sin depender de la convención de nomenclatura.
AttributeObjetivo
#[Boot]Método que se ejecuta una única vez al arrancar la clase
#[Initialize]Método que se ejecuta cada vez que se crea una instancia
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;
    }
}
Al usar PHP Attributes, el nombre del método deja de estar atado al nombre del trait, así que puedes elegir nombres realmente significativos. Además, puedes definir varios métodos #[Boot] o #[Initialize] dentro del mismo trait.

Ejemplos prácticos: uso en el desarrollo de paquetes

Añadir un global scope automáticamente

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

Añadir casts por defecto

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

Procesamiento automático mediante eventos de Eloquent

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

Ejemplos dentro del framework Laravel

El propio framework Laravel adopta este patrón en muchos de sus traits.
TraitMétodoQué hace
SoftDeletesbootSoftDeletes()Añade el global scope para soft delete
HasFactorybootHasFactory()Nada relevante (mecanismo fuera del alcance)
HasUlidsbootHasUlids()Asigna automáticamente un ULID en el evento creating
HasUuidsbootHasUuids()Asigna automáticamente un UUID en el evento creating
Leer estas implementaciones como referencia ayuda a entender el patrón con más profundidad.

Consideraciones

Limpiar la caché de modelos

Como boot* solo se ejecuta una vez por clase, hay que tener cuidado en el entorno de pruebas. Puedes resetear la caché de arranque con Model::clearBootedModels().
// Resetea el estado boot de los modelos tras cada test
protected function tearDown(): void
{
    Model::clearBootedModels();
    parent::tearDown();
}

Orden de ejecución

Cuando un mismo modelo hace use de varios traits, los métodos bootXxx() / initializeXxx() se invocan en el orden de resolución de traits de PHP (el orden de declaración). Si existen dependencias entre ellos, ten en cuenta el orden en el use.

Resumen

PatrónCómo se defineCuándo aplicarlo
Arranque de la clasestatic bootXxx() o #[Boot]Registro de eventos, adición de global scopes
Inicialización de instanciainitializeXxx() o #[Initialize]Valores por defecto, adición de casts
Implementar bootXxx() / initializeXxx() en un trait permite inyectar funcionalidad en un modelo con una sola línea use. Es el patrón habitual para añadir funciones a modelos desde un paquete.
Última modificación el 13 de julio de 2026