On this page
Caching
Gacela caches at three levels. Each solves a different problem. They work together; none replaces another.
| Layer | What it caches | Where | Typical use |
|---|---|---|---|
| Framework resolution | Resolved facades, factories, configs, merged config | Memory or disk | Always on, pick the mode per environment |
| Cacheable methods | Return values of facade methods | Memory (pluggable) | Expensive, deterministic reads |
| Value primitives | Arbitrary key → value data, optionally with a dependency graph | Disk | Your code needs its own cache (compilers, pipelines, parsed artifacts) |
Layer 1: Framework resolution cache
Gacela resolves classes by convention: Facade → Factory → Provider → Config. Those lookups walk namespaces and
files, and the merged configuration is rebuilt from every config/*.php file. Gacela memoises all of it once per
process, and can also persist it to disk between runs.
- In-memory (default):
InMemoryCacheholds resolved class names for the life of the process. - On-disk:
ClassNamePhpCache,CustomServicesPhpCache, andMergedConfigCachepersist the same data in project-scoped PHP files. Filenames include a hash of the application root, so applications that share a cache directory never serve each other's data. Merged config files are also scoped byAPP_ENV.
Turn on and tune the file cache at bootstrap with enableFileCache().
Bootstrap > File cache covers the API, how Gacela picks the cache directory, and the
GACELA_CACHE_DIR environment variable.
With the file cache on, the merged configuration auto-warms on the first miss. The first bootstrap persists the
app- and environment-scoped merged-config file, and later bootstraps skip globbing and parsing config files. That layer
needs no manual cache:warm.
Gacela trusts the two kinds of file differently. A merged-config file written by cache:warm is a deploy artifact:
Gacela serves it without looking at the config files until the next cache:warm or cache:clear. A file written on a
miss also records the config files it read. An edited, added or removed file, or a changed addAppConfig() declaration,
rebuilds it on the next bootstrap. Since 2.5
The cache holds values, not how they were computed. A config file that reads getenv('DB_HOST') is cached with the
value it read, so a different DB_HOST on the next run is not seen until cache:clear. Read a value that changes per
process in the bootstrap closure instead: $config->addAppConfigKeyValue('db.host', getenv('DB_HOST')) applies on top
of the cached values on every bootstrap and is never cached itself.
Two settings change that. Since 2.6
$config->addConfigCacheWatch('src/Config/*.php');
$config->enableVerifiedConfigCacheWarm();addConfigCacheWatch(...$paths) adds files whose change rebuilds the cache even when no config file changed. Use it
for values your own code computes, such as a config class whose output is stored. Each path is a file or a glob,
relative to the app root or absolute anywhere (a global Composer install, or phar:// inside a PHAR). A glob also
counts files added or removed. A directory counts only files added or removed directly in it, not edits to them, so
name the files.
enableVerifiedConfigCacheWarm() makes cache:warm write the checked kind instead of the trusted one. Use it for a
tool whose users warm the cache while they still edit config. It costs a stat per source on each bootstrap.
In a read-only environment, such as a read-only project root inside a build sandbox, the file caches fall back to in-memory instead of failing the bootstrap. Writes become no-ops, PHP emits no raw warnings, and pre-warmed cache files already on disk stay readable. A deployment that warms at build time and runs read-only keeps its cache hits.
Typical wiring:
- Development: file cache off. Edits take effect immediately.
- Production: file cache on, pre-populated with
vendor/bin/gacela cache:warm, directory baked into the image. Re-deploy (orcache:clear) to refresh. - Tests: call
resetInMemoryCache()between suites so resolution state does not leak.
To make PHP itself cache Gacela's source files, see Opcache preload.
Layer 2: Cacheable facade methods
Cache the result of a facade method with the #[Cacheable] attribute and $this->cached(). AbstractFacade already
includes CacheableTrait, so you need no extra use. The default storage is InMemoryCacheStorage, so on PHP-FPM
entries die with the request. To cache across requests, swap in a shared backend (APCu, Redis, PSR-16) with
CacheableConfig::setStorage().
Cacheable methods is the full reference: keys, invalidation, TTL overrides, and the storage contract.
Layer 3: Value primitives
When your code needs a cache (compiled artifacts, parsed data, a build pipeline), use
Gacela\Framework\Cache\FileCache. It writes one file per key atomically, with per-entry TTLs, batched writes, and
stats. When invalidating one entry must cascade to every entry derived from it, wrap it in ScopedCache, its
dependency-aware decorator.
Full reference: FileCache and ScopedCache.
Picking a layer
- Speed up Gacela's own resolution: Layer 1,
enableFileCache()+cache:warm. - Memoise one facade method: Layer 2,
#[Cacheable]. - Cache any application data: Layer 3,
FileCache. - The same, with cascading invalidation: Layer 3,
ScopedCache.