Caching Your Data with PHP Memcached
Memcached uses a distributed approach to storing data in RAM using a key/value store, making for ridiculously fast data caching. You’re free to begin caching data on the same Web server responsible for powering your website, and then add additional caching servers as demand increases. We’ll focus on the former task for this article, however I suggest reading through the awesome Memcached FAQ to learn more about scaling possibilities.
The key/value store is quite flexible, allowing you to store simple integers, strings, and even the results of an entire database query. The latter capability is particularly advantageous, so let’s consider an example based upon an online store which allows users to sort available games according to price. The following script will query a table named
games
for the name of all games associated with a price less than $29.99
:
<?php
// Connect to the MySQL server
$db = new mysqli("localhost", "root", "jason", "test");
$price = filter_var(29.99, FILTER_SANITIZE_NUMBER_FLOAT);
$result = $d-->query("SELECT DISTINCT name FROM games WHERE price < {$price} ORDER BY name");
while ($row = $result->fetch_assoc()){
printf("%s
", $row['name']);
}
?>
The user might be provided with a simple drop-down menu containing a list of different price filters, meaning the same set of filters (say,
$9.99
, $19.99
, $29.99
, and $39.99
) would be repeatedly used to query the database. It makes sense to cache such repetitive queries, associating their results with a key which can subsequently be used to retrieve the results in lieu of actually querying the database. I’ll present the example in its entirety, followed by a review of crucial lines.
01 <?php
02
03 $m = new Memcached();
04 $-->addServer('127.0.0.1', 11211);
05
06 $price = filter_var(29.99, FILTER_SANITIZE_NUMBER_FLOAT);
07 $price = 29.99;
08
09 $query = "SELECT DISTINCT name, publisher FROM games WHERE price < {$price} ORDER BY name";
10
11 $cacheKey = md5($query);
12
13 if (!($games = $m->get($cacheKey))) {
14
15 // Connect to the MySQL server
16 $db = new mysqli("localhost", "root", "jason", "test");
17
18 $price = filter_var(29.99, FILTER_SANITIZE_NUMBER_FLOAT);
19 $price = 29.99;
20
21 $result = $db->query($query);
22
23 $games = array();
24
25 while ($row = $result->fetch_assoc()){
26 printf("%s - %s
", $row['name'], $row['publisher']);
27 $games[] = array('name' => $row['name'], 'publisher' => $row['publisher']);
28 }
29
30 $m->set($cacheKey, $games);
31
32 } else {
33
34 foreach ($games AS $game){
35 printf("%s - %s
", $game['name'], $game['publisher']);
36
37 }
38
39 }
40
41 ?>
Let’s review the code:
- Lines 03 and 04 instantiate the Memcached class and connect to the server daemon.
- Line 11 is a convenient trick which uses the query’s MD5 hash as the query key, thereby ensuring a concise yet unique value can be constructed from each unique query.
- Line 13 uses the
get()
method to determine whether the key exists in the cache. If not, the database query is executed. - Lines 25-28 iterate over the database results, additionally adding the desired data to an array which is subsequently cached (line 30) in association with the aforementioned key.
- Lines 32-39 execute when the key is found in the cache, iterating over the results and outputting them to the browser.
Conclusion
This tutorial barely scratches the surface in terms of Memcached’s capabilities. You can set keys in association with an expiration time, delete keys, append new values to keys, retrieve cache-related statistics, and much, much more. Be sure to check out PHP’s Memcached documentation for all the details!
About the Author
Jason Gilmore is founder of the publishing, training, and consulting firm WJGilmore.com. He is the author of several popular books “Easy PHP Websites with the Zend Framework”, “Easy PayPal with PHP”, and “Beginning PHP and MySQL, Fourth Edition”. Follow him on Twitter at @wjgilmore.