On this page
Events
Gacela dispatches read-only lifecycle events as it boots, resolves services, reads config and manages caches. Listen to them for tracing, profiling, debugging or metrics — without touching your module code.
Registering listeners
Listeners are registered on GacelaConfig, in gacela.php or the Gacela::bootstrap() closure.
A generic listener — every event
registerGenericListener(callable $listener);<?php # gacela.php
use Gacela\Framework\Event\GacelaEventInterface;
return function (GacelaConfig $config) {
$config->registerGenericListener(
function (GacelaEventInterface $event): void {
error_log($event->toString());
}
);
};A specific listener — one event type
registerSpecificListener(string $event, callable $listener);<?php # gacela.php
use Gacela\Framework\Event\Bootstrap\GacelaBootstrapFinishedEvent;
return function (GacelaConfig $config) {
$config->registerSpecificListener(
GacelaBootstrapFinishedEvent::class,
function (GacelaBootstrapFinishedEvent $event): void {
error_log(sprintf('Bootstrap took %.2f ms', $event->durationMs()));
}
);
};Every event implements GacelaEventInterface, which exposes toString(): string for logging. Concrete events add typed
accessors — see the catalog below.
Lifecycle event catalog
The high-level events dispatched over a bootstrap, in the order you meet them.
Gacela\Framework\Event\Bootstrap
| Event | Dispatched when | Accessors |
|---|---|---|
GacelaBootstrapStartedEvent |
Gacela::bootstrap() begins |
appRootDir(): string |
GacelaBootstrapFinishedEvent |
bootstrap has finished | durationMs(): float |
Gacela\Framework\Event\Config
| Event | Dispatched when | Accessors |
|---|---|---|
ConfigInitializedEvent |
the merged configuration is assembled | keyCount(): int |
ConfigKeyReadEvent |
a config key is read | key(): string |
ConfigKeyNotFoundEvent |
a requested config key is missing | key(): string |
Gacela\Framework\Event\Container
| Event | Dispatched when | Accessors |
|---|---|---|
BindingRegisteredEvent |
a binding, alias or contextual binding is registered | id(): string |
ServiceResolvedEvent |
a service id is instantiated (once per id) | id(): string |
Gacela\Framework\Event\Provider
| Event | Dispatched when | Accessors |
|---|---|---|
ProviderRegisteredEvent |
a module's Provider is registered | providerClass(): string, moduleName(): string |
Gacela\Framework\Event\Cache
| Event | Dispatched when | Accessors |
|---|---|---|
CacheClearedEvent |
a cache file is removed (cache:clear) |
cacheFile(): string |
CacheWarmedEvent |
cache:warm finishes |
moduleCount(): int, failedCount(): int, skippedCount(): int |
failedCount() counts pillar classes found but not resolved. skippedCount() counts pillars a module does not contain,
which is a valid module shape. Alert on failures, not skips.
Recipes
Time the bootstrap
<?php # gacela.php
use Gacela\Framework\Event\Bootstrap\GacelaBootstrapFinishedEvent;
return function (GacelaConfig $config) {
$config->registerSpecificListener(
GacelaBootstrapFinishedEvent::class,
fn (GacelaBootstrapFinishedEvent $e) => Metrics::timing('gacela.bootstrap_ms', $e->durationMs()),
);
};Log every resolved class
<?php # gacela.php
use Gacela\Framework\Event\ClassResolver\AbstractGacelaClassResolverEvent;
use Gacela\Framework\Event\GacelaEventInterface;
return function (GacelaConfig $config) {
$config->registerGenericListener(function (GacelaEventInterface $event): void {
if ($event instanceof AbstractGacelaClassResolverEvent) {
error_log($event->toString());
}
});
};Alert on missing config keys
<?php # gacela.php
use Gacela\Framework\Event\Config\ConfigKeyNotFoundEvent;
return function (GacelaConfig $config) {
$config->registerSpecificListener(
ConfigKeyNotFoundEvent::class,
fn (ConfigKeyNotFoundEvent $e) => error_log("Missing config key: {$e->key()}"),
);
};Lower-level resolver & cache events
Beyond the lifecycle events above, Gacela dispatches fine-grained events during class resolution and cache bookkeeping.
Reach for these when tracing why a class resolved the way it did. The class-resolution events share the
AbstractGacelaClassResolverEvent base, so a single instanceof catches them all.
Gacela\Framework\Event\ClassResolver
AbstractGacelaClassResolverEvent(base type)ResolvedClassCreatedEventResolvedClassCachedEventResolvedCreatedDefaultClassEventResolvedClassTriedFromParentEvent
Gacela\Framework\Event\ClassResolver\ClassNameFinder
ClassNameValidCandidateFoundEventClassNameInvalidCandidateFoundEventClassNameCachedFoundEventClassNameNotFoundEvent
Gacela\Framework\Event\ClassResolver\Cache
ClassNameCacheCachedEventClassNamePhpCacheCreatedEventClassNameInMemoryCacheCreatedEventCustomServicesCacheCachedEventCustomServicesPhpCacheCreatedEventCustomServicesInMemoryCacheCreatedEvent
Gacela\Framework\Event\ConfigReader
ReadPhpConfigEvent
Disabling events
Turn the whole system off — no listeners fire, and Gacela swaps in a no-op dispatcher:
<?php # gacela.php
return function (GacelaConfig $config) {
$config->disableEventListeners();
};This setting wins over registrations: listeners remain configured but silently do not run. Check
disableEventListeners() first when a production listener appears inactive.
Custom dispatcher
Gacela's default dispatcher implements EventDispatcherInterface:
interface EventDispatcherInterface
{
public function dispatch(object $event): void;
// Whether any listener would receive an event of the given class,
// so hot-path dispatch sites can skip allocating the event.
public function hasListeners(string $eventClass): bool;
}See also
- Testing —
GacelaTestCaserecords these events and turns them into assertions (assertServiceResolved(),assertBindingRegistered()). - Module Customization — where listeners fit among the other
gacela.phphooks. - Bootstrap — the full
GacelaConfigsurface.