Data caching is about storing some PHP variables in cache and retrieving it later from cache. It is also the foundation for more advanced caching features, such as query caching and page caching.
The following code is a typical usage pattern of data caching, where $cache
refers to
a cache component:
// try retrieving $data from cache
$data = $cache->get($key);
if ($data === false) {
// $data is not found in cache, calculate it from scratch
$data = $this->calculateSomething();
// store $data in cache so that it can be retrieved next time
$cache->set($key, $data);
}
// $data is available here
Since version 2.0.11, cache component provides getOrSet() method that simplifies code for data getting, calculating and storing. The following code does exactly the same as the previous example:
$data = $cache->getOrSet($key, function () {
return $this->calculateSomething();
});
When cache has data associated with the $key
, the cached value will be returned.
Otherwise, the passed anonymous function will be executed to calculate the value that will be cached and returned.
If the anonymous function requires some data from the outer scope, you can pass it with the use
statement.
For example:
$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
return $this->calculateSomething($user_id);
});
Note: getOrSet() method supports duration and dependencies as well. See Cache Expiration and Cache Dependencies to know more.
Data caching relies on the so-called cache components which represent various cache storage, such as memory, files, databases.
Cache components are usually registered as application components so
that they can be globally configurable
and accessible. The following code shows how to configure the cache
application component to use
memcached with two cache servers:
'components' => [
'cache' => [
'class' => 'yii\caching\MemCache',
'servers' => [
[
'host' => 'server1',
'port' => 11211,
'weight' => 100,
],
[
'host' => 'server2',
'port' => 11211,
'weight' => 50,
],
],
],
],
You can then access the above cache component using the expression Yii::$app->cache
.
Because all cache components support the same set of APIs, you can swap the underlying cache component with a different one by reconfiguring it in the application configuration without modifying the code that uses the cache. For example, you can modify the above configuration to use APC cache:
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
],
],
Tip: You can register multiple cache application components. The component named
cache
is used by default by many cache-dependent classes (e.g. yii\web\UrlManager).
Yii supports a wide range of cache storage. The following is a summary:
false
.Yii::$app->cache->get($key)
to attempt retrieving data from the cache without worrying that
Yii::$app->cache
might be null
.Tip: You may use different cache storage in the same application. A common strategy is to use memory-based cache storage to store data that is small but constantly used (e.g. statistical data), and use file-based or database-based cache storage to store data that is big and less frequently used (e.g. page content).
All cache components have the same base class yii\caching\Cache and thus support the following APIs:
false
value will be returned if the data item is not found in the cache or is expired/invalidated.Note: Do not cache a
false
boolean value directly because the get() method usesfalse
return value to indicate the data item is not found in the cache. You may putfalse
in an array and cache this array instead to avoid this problem.
Some cache storage, such as MemCache, APC, support retrieving multiple cached values in a batch mode, which may reduce the overhead involved in retrieving cached data. The APIs multiGet() and multiAdd() are provided to exploit this feature. In case the underlying cache storage does not support this feature, it will be simulated.
Because yii\caching\Cache implements ArrayAccess
, a cache component can be used like an array. The following
are some examples:
$cache['var1'] = $value1; // equivalent to: $cache->set('var1', $value1);
$value2 = $cache['var2']; // equivalent to: $value2 = $cache->get('var2');
Each data item stored in cache is uniquely identified by a key. When you store a data item in cache, you have to specify a key for it. Later when you retrieve the data item from cache, you should provide the corresponding key.
You may use a string or an arbitrary value as a cache key. When a key is not a string, it will be automatically serialized into a string.
A common strategy of defining a cache key is to include all determining factors in terms of an array. For example, yii\db\Schema uses the following key to cache schema information about a database table:
[
__CLASS__, // schema class name
$this->db->dsn, // DB connection data source name
$this->db->username, // DB connection login user
$name, // table name
];
As you can see, the key includes all necessary information needed to uniquely specify a database table.
Note: Values stored in cache via multiSet() or multiAdd() can have only string or integer keys. If you need to set more complex key store the value separately via set() or add().
When the same cache storage is used by different applications, you should specify a unique cache key prefix for each application to avoid conflicts of cache keys. This can be done by configuring the yii\caching\Cache::$keyPrefix property. For example, in the application configuration you can write the following code:
'components' => [
'cache' => [
'class' => 'yii\caching\ApcCache',
'keyPrefix' => 'myapp', // a unique cache key prefix
],
],
To ensure interoperability, only alphanumeric characters should be used.
A data item stored in a cache will remain there forever unless it is removed because of some caching policy
enforcement (e.g. caching space is full and the oldest data are removed). To change this behavior, you can provide
an expiration parameter when calling set() to store a data item. The parameter
indicates for how many seconds the data item can remain valid in the cache. When you call
get() to retrieve the data item, if it has passed the expiration time, the method
will return false
, indicating the data item is not found in the cache. For example,
// keep the data in cache for at most 45 seconds
$cache->set($key, $data, 45);
sleep(50);
$data = $cache->get($key);
if ($data === false) {
// $data is expired or is not found in the cache
}
Since 2.0.11 you may set defaultDuration value in your cache component configuration if you prefer a custom cache duration
over the default unlimited duration.
This will allow you not to pass custom duration
parameter to set() each time.
Besides expiration setting, cached data item may also be invalidated by changes of the so-called cache dependencies.
For example, yii\caching\FileDependency represents the dependency of a file's modification time.
When this dependency changes, it means the corresponding file is modified. As a result, any outdated
file content found in the cache should be invalidated and the get() call
should return false
.
Cache dependencies are represented as objects of yii\caching\Dependency descendant classes. When you call set() to store a data item in the cache, you can pass along an associated cache dependency object. For example,
// Create a dependency on the modification time of file example.txt.
$dependency = new \yii\caching\FileDependency(['fileName' => 'example.txt']);
// The data will expire in 30 seconds.
// It may also be invalidated earlier if example.txt is modified.
$cache->set($key, $data, 30, $dependency);
// The cache will check if the data has expired.
// It will also check if the associated dependency was changed.
// It will return false if any of these conditions are met.
$data = $cache->get($key);
Below is a summary of the available cache dependencies:
Note: Avoid using exists() method along with dependencies. It does not check whether the dependency associated with the cached data, if there is any, has changed. So a call to get() may return
false
while exists() returnstrue
.
Query caching is a special caching feature built on top of data caching. It is provided to cache the result of database queries.
Query caching requires a DB connection and a valid cache
application component.
The basic usage of query caching is as follows, assuming $db
is a yii\db\Connection instance:
$result = $db->cache(function ($db) {
// the result of the SQL query will be served from the cache
// if query caching is enabled and the query result is found in the cache
return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
});
Query caching can be used for DAO as well as ActiveRecord:
$result = Customer::getDb()->cache(function ($db) {
return Customer::find()->where(['id' => 1])->one();
});
Info: Some DBMS (e.g. MySQL) also support query caching on the DB server-side. You may choose to use either query caching mechanism. The query caching described above has the advantage that you may specify flexible cache dependencies and are potentially more efficient.
Since 2.0.14 you can use the following shortcuts:
(new Query())->cache(7200)->all();
// and
User::find()->cache(7200)->all();
Query caching has three global configurable options through yii\db\Connection:
true
. Note that to effectively turn on query caching, you also need to have a valid
cache, as specified by queryCache.'cache'
. Query caching is enabled only if there is a valid cache application component.You can use yii\db\Connection::cache() if you have multiple SQL queries that need to take advantage of query caching. The usage is as follows,
$duration = 60; // cache query results for 60 seconds.
$dependency = ...; // optional dependency
$result = $db->cache(function ($db) {
// ... perform SQL queries here ...
return $result;
}, $duration, $dependency);
Any SQL queries in the anonymous function will be cached for the specified duration with the specified dependency.
If the result of a query is found valid in the cache, the query will be skipped and the result will be served
from the cache instead. If you do not specify the $duration
parameter, the value of
queryCacheDuration will be used instead.
Sometimes within cache()
, you may want to disable query caching for some particular queries. You can use
yii\db\Connection::noCache() in this case.
$result = $db->cache(function ($db) {
// SQL queries that use query caching
$db->noCache(function ($db) {
// SQL queries that do not use query caching
});
// ...
return $result;
});
If you just want to use query caching for a single query, you can call yii\db\Command::cache() when building the command. For example,
// use query caching and set query cache duration to be 60 seconds
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
You can also use yii\db\Command::noCache() to disable query caching for a single command. For example,
$result = $db->cache(function ($db) {
// SQL queries that use query caching
// do not use query caching for this command
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->noCache()->queryOne();
// ...
return $result;
});
Query caching does not work with query results that contain resource handlers. For example,
when using the BLOB
column type in some DBMS, the query result will return a resource
handler for the column data.
Some caching storage has size limitation. For example, memcache limits the maximum size of each entry to be 1MB. Therefore, if the size of a query result exceeds this limit, the caching will fail.
When you need to invalidate all the stored cache data, you can call yii\caching\Cache::flush().
You can flush the cache from the console by calling yii cache/flush
as well.
yii cache
: lists the available caches in applicationyii cache/flush cache1 cache2
: flushes the cache components cache1
, cache2
(you can pass multiple component
names separated with space)yii cache/flush-all
: flushes all cache components in the applicationyii cache/flush-schema db
: clears DB schema cache for a given connection componentInfo: Console application uses a separate configuration file by default. Ensure, that you have the same caching components in your web and console application configs to reach the proper effect.
Found a typo or you think this page needs improvement?
Edit it on github !
This is broken, if using the
where
clause
User::find()->where(['id' => $id])cache(7200)->all();
Will return the original cached result, regardless if the ID has changed. Potential solutions are 1, use the where clause as a hash for the cache, or 2 allow a cache id to be specified in addition to cache duration.
Signup or Login in order to comment.