It is my fervent wish that this file guide every AI coding agent working with code in this repository.
Any distilled, agent-facing documentation for this package - how it works
internally and the rationale behind key design decisions - lives in docs/.
Consult it before non-trivial changes; it is the source of truth from which the
public manual is distilled.
Cache -> Storage -> Journal is one layered mechanism whose traps only make
sense together (overloaded null, dependency desugaring, the cross-method lock,
the FileStorage format). Read docs/internals.md before editing them.
docs/upgrading.md records, per released version, every change visible to
users of the package (renames, removals, deprecations, signatures, behavior,
configuration), each with its commit hash; internal changes are not in it. It
is the place to look up the history of a public symbol. Do not write to it; it
is extended at release time from the git history.
Nette Caching provides flexible caching with pluggable storage backends
(File, SQLite, Memcached, Redis, Memory, DevNull), rich dependency tracking
(expiration, tags, files, callbacks), PSR-16 bridges in both directions
(PsrCacheAdapter, Psr16Storage), and a Latte {cache} tag. Part of the
Nette Framework, usable standalone.
- PHP Version: 8.3 - 8.6
- Package:
nette/caching
# Run all tests
vendor/bin/tester tests -s # or: composer tester
# Run one test directory / file
vendor/bin/tester tests/Storages -s
php tests/Caching/Cache.bulkLoad.phpt
# Static analysis (PHPStan level 8)
composer phpstan- Every file starts with
declare(strict_types=1);; Nette Coding Standard. - Tests are Nette Tester
.phptfiles undertests/;tests/bootstrap.phpprovidestest()andgetTempDir()(isolated per-process temp dir). - Constants are modern PascalCase (
Cache::Expire) with deprecated UPPERCASE aliases (Cache::EXPIRATION) kept for BC; theStorageinterface wasIStoragebefore v3.1.
nullis overloaded:save($key, null)isremove().nullmeans cache miss on read, delete on write, and an already-expiredExpirealso deletes. Never add a path that storesnullas a real value.- Dependencies are desugared before storages see them (
completeDependencies):Files/ConstantsbecomeCallbacks,Expirebecomes a relative second count. Reason about a backend's support from the post-desugar set, not the public constant list. - The lock spans two calls -
Cachelocks before running a generator, andwrite()/remove()release it. Stampede protection is real only inFileStorage; every other backend'slock()is a no-op. MemoryStoragehonors onlyExpire,Sliding,TagsandPriority;Callbacks(soFiles/Constants),ItemsandNamespacesare silently ignored - a trap when it stands in for a real backend.- Unsupported dependencies throw.
SQLiteStorage,MemcachedStorage,RedisStorageandPsr16StoragethrowNotSupportedExceptionfor a dependency or clean condition they cannot honor. - FileStorage writes the real header last (it doubles as a commit marker). Its
constructor probabilistically runs a GC batch limited to 20 ms; only an
explicit
clean([])walks the whole cache. RedisStorageneeds no Journal: tags, priorities and namespaces live in auxiliary keys prefixed with"\x01"; the set of tags of an item does not expire with it. Expired items leave their entries there untilclean([]), run probabilistically by the constructor, removes them. The default prefix isnette.cache:; an empty one makes the whole database the cache andclean(All)callsflushDB().Psr16Storagehashes keys (xxh128) to the PSR-16 safe charset and needs a Journal for tags and priorities;Slidingis not supported, andclean(All)clears the whole underlying PSR-16 cache regardless of the prefix.- User-facing how-to (DI wiring, storage/journal config, PSR-16 usage,
{cache}tag) is manual material and lives in the public web docs, not here.