Event Registration

Event Discovery and Manual Registration

At boot, event discovery reflects over app/Listeners and registers each public handle* or __invoke method for the event type-hinted on its first parameter (a union type registers it for each). Anything else goes in AppServiceProvider::boot(), where a closure's event also comes from its type hint:

Registering a closure listener in AppServiceProvider::boot()PHP
Event::listen(function (ProductRestocked $event) {
    Log::info("Restocked {$event->product->sku} (+{$event->added})");
});
Output
$ php artisan event:list --event='App\Events'
  App\Events\OrderPlaced .....................................................
  ⇂ App\Listeners\CatalogCacheSubscriber@forgetAfterSale
  ⇂ App\Listeners\NotifyWarehouse@handle (ShouldQueue)
  ⇂ App\Listeners\ReserveStock@handle
  ⇂ App\Listeners\SendOrderConfirmation@handle
  App\Events\ProductRestocked ................................................
  ⇂ App\Listeners\CatalogCacheSubscriber@forgetAfterRestock
  ⇂ Closure at: /app/Providers/AppServiceProvider.php:31

->withEvents(discover: [...]) in bootstrap/app.php scans other folders. Deployments run php artisan event:cache (or optimize, Config and Route Caching) to write bootstrap/cache/events.php. A listener added after that is ignored until you cache again, the usual cause of "my listener never runs".