Output Caching With PHP

 In Uncategorized

Output Caching With PHP

By Tech Operative

We all know that PHP is not always fast, but achieving good performance is possible through the use of various forms of caching. Today I would like to talk about output caching. Output caching involves saving a page’s output to a file, so that the next time someone requests that file, we will simply output the saved cache file instead of re-processing that entire page. To go even further with this idea, you would want to cache individual blocks of that page instead of the entire page. Each cache file would be used for a specified length of time, and then regenerated after that time has expired. This is a great way to speed up code especially if you have pages that make database calls, and do not necessarily need to be updated each and every time the page is loaded.

To perform our output caching, we need to become familiar with the ob_start() and ob_get_flush() functions. ob_start() will begin buffering anything that we output to the page, and ob_get_flush() will give us the contents of the output buffer as well as flush the buffer.

My output caching class includes begin and end caching methods. The begin caching method looks like this.

[code language=”plain”]currentOutputFile) throw new Exception(‘You must end your previous caching before beginning a new one.’, E_USER_ERROR);     $this->currentOutputFile = ‘application/cache/’ . crc32($cache_id);     $this->expireDuration = $expire_duration;          // if cache file exists     if (is_readable($this->currentOutputFile)) {         if (!$this->cacheExpired()) {             // output it             echo file_get_contents($this->currentOutputFile);             return false;         }     }          ob_start();     return true; } [/code]


You can see that the method has two arguments. The first argument gives the cache file a unique name, while the second argument gives the cache file an expiration date. I use crc32 hashing on the cache id in order to give it a fixed length, and make it file name safe. In larger programs you may need to use a slower hashing function in order to prevent collision. The cache id input can be a concatenation of the request path, the particular page block name, and whatever other variables make that output block unique. Whatever the cache id is, it must be the same each time that particular output block is requested.

If the cache file already exists, and it was last modified longer ago than the set expire duration, then we will create a new cache file, otherwise we will simply output the cache file and return true. The return value lets us know whether we need to process and output the page or page block as normal, or if we can skip all of that. If we do need to process the page as normal, we will start output buffering with the ob_start() function so that we can save a new cache file.

Now at the end of the page or page block that we are caching, we need to use a method that will save our cache file, which should look something like this.

[code language=”plain”]currentOutputFile) throw new Exception(‘You must begin a cache buffer before you can end it.’, E_USER_ERROR);          // create buffer file     if ($this->cacheExpired()) {         $file = fopen($this->currentOutputFile, ‘c’);         if (flock($file, LOCK_EX)) {             ftruncate($file, 0);             fwrite($file, ob_get_flush());         } else {             ob_flush();         }         fclose($file);     } [/code]


This will save the buffer into a cache file, and unset the current cache file’s name. You will want to encapsulate these methods into a class which we will call OutputCache. The implementation of this code may seem strange at first, but you will see that it is necessary. If you want to cache multiple blocks on one page, implementation looks something like this.

[code language=”plain”]beginCache($unique_name_for_this_page_output)) {     // process and output page or page block as normal          $output_cache->endCache(); } ?>[/code]


So if we are beginning caching (no usable cache file exists already), process and output the page block as normal, otherwise, skip the processing and output for that page block, and simply output the contents of the cache file.

If you are simply caching an entire page, implimentation is a bit simpler.

[code language=”plain”]begin_cache($unique_name_for_this_page_output)) exit; // process and output page as normal      $output_cache->endCache(); ?>[/code]


This implementation does not require your page processing and output to be wrapped in a conditional.

The final class may look something like this.

[code language=”plain”]currentOutputFile) trigger_error(‘You must end your previous caching before beginning a new one.’, E_USER_ERROR);              $this->currentOutputFile = __DIR__ . ‘/OutputCache/cache/’ . crc32($cache_id);         $this->expireDuration = $expire_duration;                  // if cache file exists         if (is_readable($this->currentOutputFile)) {             if (!$this->cacheExpired()) {                 // output it                 echo file_get_contents($this->currentOutputFile);                 return false;             }         }                  ob_start();         return true;     }          // end output caching     public static function endCache() {              // if output buffer has not yet been started, throw and error         if (!$this->currentOutputFile) trigger_error(‘You must begin a cache buffer before you can end it.’, E_USER_ERROR); [/code]


Tags: #php #cache#caching#output-caching#output-buffer

Leave a Comment

Contact Us

We're not around right now. But you can send us an email and we'll get back to you, asap.