• Stars
    star
    390
  • Rank 106,307 (Top 3 %)
  • Language
    PHP
  • License
    Other
  • Created about 10 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

⏱ Caching library with easy-to-use API and many cache backends.

Nette Caching

Downloads this Month Tests Coverage Status Latest Stable Version License

Introduction

Cache accelerates your application by storing data - once hardly retrieved - for future use.

Documentation can be found on the website.

Support Me

Do you like Nette Caching? Are you looking forward to the new features?

Buy me a coffee

Thank you!

Installation

composer require nette/caching

It requires PHP version 8.0 and supports PHP up to 8.3.

Basic Usage

The center of work with the cache is the object Nette\Caching\Cache. 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.

For the following examples, suppose we have an alias Cache and a storage in the variable $storage.

use Nette\Caching\Cache;

$storage // instance of Nette\Caching\IStorage

The 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.

The name of the space is specified as the second parameter of the constructor of the Cache class:

$cache = new Cache($storage, 'Full Html Pages');

We 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:

$value = $cache->load($key, function () use ($key) {
	$computedValue = ...; // heavy computations
	return $computedValue;
});

If the second parameter is not specified $value = $cache->load($key), the null is returned if the item is not in the cache.

The great thing is that any serializable structures can be cached, not only strings. And the same applies for keys.

The item is cleared from the cache using method remove():

$cache->remove($key);

You can also cache an item using method $cache->save($key, $value, array $dependencies = []). However, the above method using load() is preferred.

Memoization

Memoization 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.

Methods and functions can be called memoized using call(callable $callback, ...$args):

$result = $cache->call('gethostbyaddr', $ip);

The function gethostbyaddr() is called only once for each parameter $ip and the next time the value from the cache will be returned.

It is also possible to create a memoized wrapper for a method or function that can be called later:

function factorial($num)
{
	return ...;
}

$memoizedFactorial = $cache->wrap('factorial');

$result = $memoizedFactorial(5); // counts it
$result = $memoizedFactorial(5); // returns it from cache

Expiration & Invalidation

With 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).

The validity of the data is set at the time of saving using the third parameter of the method save(), eg:

$cache->save($key, $value, [
	Cache::Expire => '20 minutes',
]);

Or using the $dependencies parameter passed by reference to the callback in the load() method, eg:

$value = $cache->load($key, function (&$dependencies) {
	$dependencies[Cache::Expire] = '20 minutes';
	return ...;
]);

Or using 3rd parameter in the load() method, eg:

$value = $cache->load($key, function () {
	return ...;
], [Cache::Expire => '20 minutes']);

In the following examples, we will assume the second variant and thus the existence of a variable $dependencies.

Expiration

The simplest exiration is the time limit. Here's how to cache data valid for 20 minutes:

// it also accepts the number of seconds or the UNIX timestamp
$dependencies[Cache::Expire] = '20 minutes';

If we want to extend the validity period with each reading, it can be achieved this way, but beware, this will increase the cache overhead:

$dependencies[Cache::Sliding] = true;

The 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.

$dependencies[Cache::Files] = '/path/to/data.yaml';
// nebo
$dependencies[Cache::Files] = ['/path/to/data1.yaml', '/path/to/data2.yaml'];

We 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:

$dependencies[Cache::Items] = ['frag1', 'frag2'];

Expiration 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:

function checkPhpVersion($ver): bool
{
	return $ver === PHP_VERSION_ID;
}

$dependencies[Cache::Callbacks] = [
	['checkPhpVersion', PHP_VERSION_ID] // expire when checkPhpVersion(...) === false
];

Of course, all criteria can be combined. The cache then expires when at least one criterion is not met.

$dependencies[Cache::Expire] = '20 minutes';
$dependencies[Cache::Files] = '/path/to/data.yaml';

Invalidation using Tags

Tags 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:

$dependencies[Cache::Tags] = ["article/$articleId", "comments/$articleId"];

Now, 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:

$cache->clean([
	Cache::Tags => ["article/$articleId"],
]);

Likewise, in the place of adding a new comment (or editing a comment), we will not forget to invalidate the relevant tag:

$cache->clean([
	Cache::Tags => ["comments/$articleId"],
]);

What 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.

Tags require Journal.

Invalidation by Priority

We 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:

$dependencies[Cache::Priority] = 50;

Delete all items with a priority equal to or less than 100:

$cache->clean([
	Cache::Priority => 100,
]);

Priorities require so-called Journal.

Clear Cache

The Cache::All parameter clears everything:

$cache->clean([
	Cache::All => true,
]);

Bulk Reading

For bulk reading and writing to cache, the bulkLoad() method is used, where we pass an array of keys and obtain an array of values:

$values = $cache->bulkLoad($keys);

Method bulkLoad() works similarly to load() with the second callback parameter, to which the key of the generated item is passed:

$values = $cache->bulkLoad($keys, function ($key, &$dependencies) {
	$computedValue = ...; // heavy computations
	return $computedValue;
});

Output Caching

The output can be captured and cached very elegantly:

if ($capture = $cache->start($key)) {

	echo ... // printing some data

	$capture->end(); // save the output to the cache
}

In 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.

Caching in Latte

Caching in templates Latte 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.

In 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.

{cache $id, expire => '20 minutes', tags => [tag1, tag2]}
	...
{/cache}

All parameters are optional, so you don't have to specify expiration, tags, or keys.

The use of the cache can also be conditioned by if - the content will then be cached only if the condition is met:

{cache $id, if => !$form->isSubmitted()}
	{$form}
{/cache}

Storages

A 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.

Storage Description
FileStorage default storage with saving to files on disk
MemcachedStorage uses the Memcached server
MemoryStorage data are temporarily in memory
SQLiteStorage data is stored in SQLite database
DevNullStorage data aren't stored - for testing purposes

FileStorage

Writes 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.

This 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 prevention. It 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. The 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. Fortunately, 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.

Example of creating a FileStorage:

// the storage will be the directory '/path/to/temp' on the disk
$storage = new Nette\Caching\Storages\FileStorage('/path/to/temp');

MemcachedStorage

The server Memcached is a high-performance distributed storage system whose adapter is Nette\Caching\Storages\MemcachedStorage.

Requires PHP extension memcached.

$storage = new Nette\Caching\Storages\MemcachedStorage('10.0.0.158');

MemoryStorage

Nette\Caching\Storages\MemoryStorage is a storage that stores data in a PHP array and is thus lost when the request is terminated.

$storage = new Nette\Caching\Storages\MemoryStorage;

SQLiteStorage

The 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.

Requires PHP extensions pdo and pdo_sqlite.

$storage = new Nette\Caching\Storages\SQLiteStorage('/path/to/cache.sdb');

DevNullStorage

A 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.

$storage = new Nette\Caching\Storages\DevNullStorage;

Journal

Nette 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.

If you like Nette, please make a donation now. Thank you!

More Repositories

1

php-generator

🐘 Generates neat PHP code for you. Supports new PHP 8.3 features.
PHP
1,978
star
2

utils

πŸ›  Lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.
PHP
1,868
star
3

tracy

😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.
PHP
1,712
star
4

nette

πŸ‘ͺ METAPACKAGE for Nette Framework components
PHP
1,514
star
5

latte

β˜• Latte: the safest & truly intuitive templates for PHP. Engine for those who want the most secure PHP sites.
PHP
1,044
star
6

finder

πŸ” Finder: find files and directories with an intuitive API.
931
star
7

neon

🍸 Encodes and decodes NEON file format.
PHP
879
star
8

robot-loader

πŸ€ RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.
PHP
854
star
9

di

πŸ’Ž Flexible, compiled and full-featured Dependency Injection Container with perfectly usable autowiring and support for all new PHP 7 features.
PHP
841
star
10

schema

πŸ“ Validating data structures against a given Schema.
PHP
811
star
11

bootstrap

πŸ…± The simple way to configure and bootstrap your Nette application.
PHP
654
star
12

forms

πŸ“ Generating, validating and processing secure forms in PHP. Handy API, fully customizable, server & client side validation and mature design.
PHP
470
star
13

database

πŸ’Ύ A database layer with a familiar PDO-like API but much more powerful. Building queries, advanced joins, drivers for MySQL, PostgreSQL, SQLite, MS SQL Server and Oracle.
PHP
470
star
14

mail

A handy library for creating and sending emails in PHP
PHP
448
star
15

tester

Tester: enjoyable unit testing in PHP with code coverage reporter. 🍏🍏🍎🍏
PHP
440
star
16

http

🌐 Abstraction for HTTP request, response and session. Provides careful data sanitization and utility for URL and cookies manipulation.
PHP
437
star
17

application

πŸ† A full-stack component-based MVC kernel for PHP that helps you write powerful and modern web applications. Write less, have cleaner code and your work will bring you joy.
PHP
384
star
18

security

πŸ”‘ Provides authentication, authorization and a role-based access control management via ACL (Access Control List)
PHP
338
star
19

component-model

βš› Component model foundation for Nette.
PHP
251
star
20

routing

Nette Routing: two-ways URL conversion
PHP
220
star
21

sandbox

142
star
22

tokenizer

[DISCONTINUED] Source code tokenizer
PHP
141
star
23

safe-stream

SafeStream: atomic and safe manipulation with files via native PHP functions.
PHP
117
star
24

docs

πŸ“– The Nette documentation
115
star
25

web-project

Standard Web Project: a simple skeleton application using the Nette
Latte
102
star
26

reflection

[DISCONTINUED] Docblock annotations parser and common reflection classes
PHP
94
star
27

examples

πŸŽ“ Examples demonstrating the Nette Framework.
88
star
28

code-checker

βœ… A simple tool to check source code against a set of Nette coding standards.
PHP
85
star
29

web-addons.nette.org

[DISCONTINUED] Website https://addons.nette.org source code.
PHP
55
star
30

coding-standard

Nette Coding Standard code checker & fixer
PHP
40
star
31

command-line

⌨ Command line options and arguments parser.
PHP
37
star
32

type-fixer

πŸ†™ A tool to automatically update typehints in your code.
PHP
29
star
33

resources

Client-side resources for Nette Framework.
23
star
34

latte-tools

Twig & HTML to Latte converters
PHP
22
star
35

grunt-nette-tester

Grunt plugin for Nette Tester
JavaScript
20
star
36

middleware

PHP
20
star
37

deprecated

[DISCONTINUED] APIs and features removed from Nette Framework
PHP
19
star
38

safe

πŸ›‘ PHP functions smarten up to throw exceptions instead of returning false or triggering errors.
PHP
17
star
39

nette-minified

[DISCONTINUED] Minified version of Nette Framework.
PHP
16
star
40

tutorial-todo

[DISCONTINUED] Tutorial for simple task manager.
PHP
10
star
41

union

[READ-ONLY] Subtree union of Nette repositories
PHP
7
star
42

assistant

PHP
3
star
43

.github

1
star