{"id":13409953,"url":"https://github.com/nette/caching","last_synced_at":"2026-02-26T01:18:18.847Z","repository":{"id":14969005,"uuid":"17693928","full_name":"nette/caching","owner":"nette","description":"⏱ Caching library with easy-to-use API and many cache backends.","archived":false,"fork":false,"pushed_at":"2024-08-13T20:20:18.000Z","size":717,"stargazers_count":418,"open_issues_count":17,"forks_count":44,"subscribers_count":35,"default_branch":"master","last_synced_at":"2025-04-10T02:58:45.775Z","etag":null,"topics":["atomicity","cache","expiration","memcached","nette","nette-framework","php","storage"],"latest_commit_sha":null,"homepage":"https://doc.nette.org/caching","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"tiansiyuan/react-native-guide","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nette.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"dg","custom":"https://nette.org/donate"}},"created_at":"2014-03-13T03:43:57.000Z","updated_at":"2025-02-11T18:54:14.000Z","dependencies_parsed_at":"2023-02-19T11:31:23.449Z","dependency_job_id":"fe8c587f-b55d-4af7-81ec-e2995d9c09de","html_url":"https://github.com/nette/caching","commit_stats":{"total_commits":506,"total_committers":32,"mean_commits":15.8125,"dds":"0.16403162055335974","last_synced_commit":"fb5c89d9a8c831eb7b67a2acfa2ff97dfc21202c"},"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fcaching","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fcaching/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fcaching/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nette%2Fcaching/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nette","download_url":"https://codeload.github.com/nette/caching/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248368704,"owners_count":21092436,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["atomicity","cache","expiration","memcached","nette","nette-framework","php","storage"],"created_at":"2024-07-30T20:01:04.208Z","updated_at":"2026-02-26T01:18:18.835Z","avatar_url":"https://github.com/nette.png","language":"PHP","readme":"Nette Caching\n=============\n\n[![Downloads this Month](https://img.shields.io/packagist/dm/nette/caching.svg)](https://packagist.org/packages/nette/caching)\n[![Tests](https://github.com/nette/caching/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/caching/actions)\n[![Coverage Status](https://coveralls.io/repos/github/nette/caching/badge.svg?branch=master)](https://coveralls.io/github/nette/caching?branch=master)\n[![Latest Stable Version](https://poser.pugx.org/nette/caching/v/stable)](https://github.com/nette/caching/releases)\n[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/caching/blob/master/license.md)\n\n\nIntroduction\n============\n\nCache accelerates your application by storing data - once hardly retrieved - for future use.\n\nDocumentation can be found on the [website](https://doc.nette.org/caching).\n\n\n[Support Me](https://github.com/sponsors/dg)\n--------------------------------------------\n\nDo you like Nette Caching? Are you looking forward to the new features?\n\n[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)\n\nThank you!\n\n\nInstallation\n------------\n\n```\ncomposer require nette/caching\n```\n\nIt requires PHP version 8.1 and supports PHP up to 8.5.\n\n\nBasic Usage\n===========\n\nThe center of work with the cache is the object [Nette\\Caching\\Cache](https://api.nette.org/3.0/Nette/Caching/Cache.html). We create its instance and pass the so-called storage to the constructor as a parameter. Which is an object representing the place where the data will be physically stored (database, Memcached, files on disk, ...). You will find out all the essentials in [section Storages](#Storages).\n\nFor the following examples, suppose we have an alias `Cache` and a storage in the variable `$storage`.\n\n```php\nuse Nette\\Caching\\Cache;\n\n$storage // instance of Nette\\Caching\\IStorage\n```\n\nThe cache is actually a *key–value store*, so we read and write data under keys just like associative arrays. Applications consist of a number of independent parts, and if they all used one storage (for idea: one directory on a disk), sooner or later there would be a key collision. The Nette Framework solves the problem by dividing the entire space into namespaces (subdirectories). Each part of the program then uses its own space with a unique name and no collisions can occur.\n\nThe name of the space is specified as the second parameter of the constructor of the Cache class:\n\n```php\n$cache = new Cache($storage, 'Full Html Pages');\n```\n\nWe can now use object `$cache` to read and write from the cache. The method `load()` is used for both. The first argument is the key and the second is the PHP callback, which is called when the key is not found in the cache. The callback generates a value, returns it and caches it:\n\n```php\n$value = $cache-\u003eload($key, function () use ($key) {\n\t$computedValue = ...; // heavy computations\n\treturn $computedValue;\n});\n```\n\nIf the second parameter is not specified `$value = $cache-\u003eload($key)`, the `null` is returned if the item is not in the cache.\n\nThe great thing is that any serializable structures can be cached, not only strings. And the same applies for keys.\n\nThe item is cleared from the cache using method `remove()`:\n\n```php\n$cache-\u003eremove($key);\n```\n\nYou can also cache an item using method `$cache-\u003esave($key, $value, array $dependencies = [])`. However, the above method using `load()` is preferred.\n\n\n\n\nMemoization\n===========\n\nMemoization means caching the result of a function or method so you can use it next time instead of calculating the same thing again and again.\n\nMethods and functions can be called memoized using `call(callable $callback, ...$args)`:\n\n```php\n$result = $cache-\u003ecall('gethostbyaddr', $ip);\n```\n\nThe function `gethostbyaddr()` is called only once for each parameter `$ip` and the next time the value from the cache will be returned.\n\nIt is also possible to create a memoized wrapper for a method or function that can be called later:\n\n```php\nfunction factorial($num)\n{\n\treturn ...;\n}\n\n$memoizedFactorial = $cache-\u003ewrap('factorial');\n\n$result = $memoizedFactorial(5); // counts it\n$result = $memoizedFactorial(5); // returns it from cache\n```\n\n\nExpiration \u0026 Invalidation\n=========================\n\nWith caching, it is necessary to address the question that some of the previously saved data will become invalid over time. Nette Framework provides a mechanism, how to limit the validity of data and how to delete them in a controlled way (\"to invalidate them\", using the framework's terminology).\n\nThe validity of the data is set at the time of saving using the third parameter of the method `save()`, eg:\n\n```php\n$cache-\u003esave($key, $value, [\n\tCache::Expire =\u003e '20 minutes',\n]);\n```\n\nOr using the `$dependencies` parameter passed by reference to the callback in the `load()` method, eg:\n\n```php\n$value = $cache-\u003eload($key, function (\u0026$dependencies) {\n\t$dependencies[Cache::Expire] = '20 minutes';\n\treturn ...;\n]);\n```\n\nOr using 3rd parameter in the `load()` method, eg:\n\n```php\n$value = $cache-\u003eload($key, function () {\n\treturn ...;\n], [Cache::Expire =\u003e '20 minutes']);\n```\n\nIn the following examples, we will assume the second variant and thus the existence of a variable `$dependencies`.\n\n\nExpiration\n----------\n\nThe simplest exiration is the time limit. Here's how to cache data valid for 20 minutes:\n\n```php\n// it also accepts the number of seconds or the UNIX timestamp\n$dependencies[Cache::Expire] = '20 minutes';\n```\n\nIf we want to extend the validity period with each reading, it can be achieved this way, but beware, this will increase the cache overhead:\n\n```php\n$dependencies[Cache::Sliding] = true;\n```\n\nThe handy option is the ability to let the data expire when a particular file is changed or one of several files. This can be used, for example, for caching data resulting from procession these files. Use absolute paths.\n\n```php\n$dependencies[Cache::Files] = '/path/to/data.yaml';\n// nebo\n$dependencies[Cache::Files] = ['/path/to/data1.yaml', '/path/to/data2.yaml'];\n```\n\nWe can let an item in the cache expired when another item (or one of several others) expires. This can be used when we cache the entire HTML page and fragments of it under other keys. Once the snippet changes, the entire page becomes invalid. If we have fragments stored under keys such as `frag1` and `frag2`, we will use:\n\n```php\n$dependencies[Cache::Items] = ['frag1', 'frag2'];\n```\n\nExpiration can also be controlled using custom functions or static methods, which always decide when reading whether the item is still valid. For example, we can let the item expire whenever the PHP version changes. We will create a function that compares the current version with the parameter, and when saving we will add an array in the form `[function name, ...arguments]` to the dependencies:\n\n```php\nfunction checkPhpVersion($ver): bool\n{\n\treturn $ver === PHP_VERSION_ID;\n}\n\n$dependencies[Cache::Callbacks] = [\n\t['checkPhpVersion', PHP_VERSION_ID] // expire when checkPhpVersion(...) === false\n];\n```\n\nOf course, all criteria can be combined. The cache then expires when at least one criterion is not met.\n\n```php\n$dependencies[Cache::Expire] = '20 minutes';\n$dependencies[Cache::Files] = '/path/to/data.yaml';\n```\n\n\n\nInvalidation using Tags\n-----------------------\n\nTags are a very useful invalidation tool. We can assign a list of tags, which are arbitrary strings, to each item stored in the cache. For example, suppose we have an HTML page with an article and comments, which we want to cache. So we specify tags when saving to cache:\n\n```php\n$dependencies[Cache::Tags] = [\"article/$articleId\", \"comments/$articleId\"];\n```\n\nNow, let's move to the administration. Here we have a form for article editing. Together with saving the article to a database, we call the `clean()` command, which will delete cached items by tag:\n\n```php\n$cache-\u003eclean([\n\tCache::Tags =\u003e [\"article/$articleId\"],\n]);\n```\n\nLikewise, in the place of adding a new comment (or editing a comment), we will not forget to invalidate the relevant tag:\n\n```php\n$cache-\u003eclean([\n\tCache::Tags =\u003e [\"comments/$articleId\"],\n]);\n```\n\nWhat have we achieved? That our HTML cache will be invalidated (deleted) whenever the article or comments change. When editing an article with ID = 10, the tag `article/10` is forced to be invalidated and the HTML page carrying the tag is deleted from the cache. The same happens when you insert a new comment under the relevant article.\n\nTags require [Journal](#Journal).\n\n\nInvalidation by Priority\n------------------------\n\nWe can set the priority for individual items in the cache, and it will be possible to delete them in a controlled way when, for example, the cache exceeds a certain size:\n\n```php\n$dependencies[Cache::Priority] = 50;\n```\n\nDelete all items with a priority equal to or less than 100:\n\n```php\n$cache-\u003eclean([\n\tCache::Priority =\u003e 100,\n]);\n```\n\nPriorities require so-called [Journal](#Journal).\n\n\nClear Cache\n-----------\n\nThe `Cache::All` parameter clears everything:\n\n```php\n$cache-\u003eclean([\n\tCache::All =\u003e true,\n]);\n```\n\n\nBulk Reading\n============\n\nFor bulk reading and writing to cache, the `bulkLoad()` method is used, where we pass an array of keys and obtain an array of values:\n\n```php\n$values = $cache-\u003ebulkLoad($keys);\n```\n\nMethod `bulkLoad()` works similarly to `load()` with the second callback parameter, to which the key of the generated item is passed:\n\n```php\n$values = $cache-\u003ebulkLoad($keys, function ($key, \u0026$dependencies) {\n\t$computedValue = ...; // heavy computations\n\treturn $computedValue;\n});\n```\n\n\nOutput Caching\n==============\n\nThe output can be captured and cached very elegantly:\n\n```php\nif ($capture = $cache-\u003estart($key)) {\n\n\techo ... // printing some data\n\n\t$capture-\u003eend(); // save the output to the cache\n}\n```\n\nIn case that the output is already present in the cache, the `start()` method prints it and returns `null`, so the condition will not be executed. Otherwise, it starts to buffer the output and returns the `$capture` object using which we finally save the data to the cache.\n\n\nCaching in Latte\n================\n\nCaching in templates [Latte](https://latte.nette.org) is very easy, just wrap part of the template with tags `{cache}...{/cache}`. The cache is automatically invalidated when the source template changes (including any included templates within the `{cache}` tags). Tags `{cache}` can be nested, and when a nested block is invalidated (for example, by a tag), the parent block is also invalidated.\n\nIn the tag it is possible to specify the keys to which the cache will be bound (here the variable `$id`) and set the expiration and [invalidation tags](#invalidation-using-tags).\n\n```html\n{cache $id, expire =\u003e '20 minutes', tags =\u003e [tag1, tag2]}\n\t...\n{/cache}\n```\n\nAll parameters are optional, so you don't have to specify expiration, tags, or keys.\n\nThe use of the cache can also be conditioned by `if` - the content will then be cached only if the condition is met:\n\n```html\n{cache $id, if =\u003e !$form-\u003eisSubmitted()}\n\t{$form}\n{/cache}\n```\n\n\nStorages\n========\n\nA storage is an object that represents where data is physically stored. We can use a database, a Memcached server, or the most available storage, which are files on disk.\n\nStorage | \t\t\tDescription\n--------|----------------------\nFileStorage | \t\tdefault storage with saving to files on disk\nMemcachedStorage | \tuses the `Memcached` server\nMemoryStorage | \tdata are temporarily in memory\nSQLiteStorage | \tdata is stored in SQLite database\nDevNullStorage | \tdata aren't stored - for testing purposes\n\n\nFileStorage\n-----------\n\nWrites the cache to files on disk. The storage `Nette\\Caching\\Storages\\FileStorage` is very well optimized for performance and above all ensures full atomicity of operations. What does it mean? That when using the cache, it cannot happen that we read a file that has not yet been completely written by another thread, or that someone would delete it \"under your hands\". The use of the cache is therefore completely safe.\n\nThis storage also has an important built-in feature that prevents an extreme increase in CPU usage when the cache is cleared or cold (ie not created). This is [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede) prevention.\nIt happens that at one moment there are several concurrent requests that want the same thing from the cache (eg the result of an expensive SQL query) and because it is not cached, all processes start executing the same SQL query.\nThe processor load is multiplied and it can even happen that no thread can respond within the time limit, the cache is not created and the application crashes.\nFortunately, the cache in Nette works in such a way that when there are multiple concurrent requests for one item, it is generated only by the first thread, the others wait and then use the generated result.\n\nExample of creating a FileStorage:\n\n```php\n// the storage will be the directory '/path/to/temp' on the disk\n$storage = new Nette\\Caching\\Storages\\FileStorage('/path/to/temp');\n```\n\nMemcachedStorage\n----------------\n\nThe server [Memcached](https://memcached.org) is a high-performance distributed storage system whose adapter is `Nette\\Caching\\Storages\\MemcachedStorage`.\n\nRequires PHP extension `memcached`.\n\n```php\n$storage = new Nette\\Caching\\Storages\\MemcachedStorage('10.0.0.158');\n```\n\nMemoryStorage\n-------------\n\n`Nette\\Caching\\Storages\\MemoryStorage` is a storage that stores data in a PHP array and is thus lost when the request is terminated.\n\n```php\n$storage = new Nette\\Caching\\Storages\\MemoryStorage;\n```\n\n\nSQLiteStorage\n-------------\n\nThe SQLite database and adapter `Nette\\Caching\\Storages\\SQLiteStorage` offer a way to cache in a single file on disk. The configuration will specify the path to this file.\n\nRequires PHP extensions `pdo` and `pdo_sqlite`.\n\n```php\n$storage = new Nette\\Caching\\Storages\\SQLiteStorage('/path/to/cache.sdb');\n```\n\n\nDevNullStorage\n--------------\n\nA special implementation of storage is `Nette\\Caching\\Storages\\DevNullStorage`, which does not actually store data at all. It is therefore suitable for testing if we want to eliminate the effect of the cache.\n\n```php\n$storage = new Nette\\Caching\\Storages\\DevNullStorage;\n```\n\n\nJournal\n=======\n\nNette stores tags and priorities in a so-called journal. By default, SQLite and file `journal.s3db` are used for this, and **PHP extensions `pdo` and `pdo_sqlite` are required.**\n\nIf you like Nette, **[please make a donation now](https://github.com/sponsors/dg)**. Thank you!\n","funding_links":["https://github.com/sponsors/dg","https://nette.org/donate","https://github.com/sponsors/dg)*"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fcaching","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnette%2Fcaching","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnette%2Fcaching/lists"}