PHP DevCenter

oreilly.comSafari Books Online.Conferences.

We've expanded our LAMP news coverage and improved our search! Search for all things LAMP across O'Reilly!

Search
Search Tips

advertisement

Print Subscribe to PHP Subscribe to Newsletters

Caching PHP Programs with PEAR
Pages: 1, 2

Output caching

Looking back at the introductory example of a commerce application, you're now able to cache parsed template elements, or catalog information you used to pull from the database on each request.



We now go a step further and cache a script's complete output with the Cache_Output class.

Example 2: Caching a script's output

<?php
// Load PEAR Cache's Output Cache

require_once 'Cache/Output.php';

$cache = new Cache_Output('file', array('cache_dir' => '.') );

// Compute unique cache identifier for the page we're about
// to cache. We'll assume that the page's output depends on
// the URL, HTTP GET and POST variables and cookies.

$cache_id = $cache->generateID(array('url' => $REQUEST_URI, 'post' => $HTTP_POST_VARS, 'cookies' => $HTTP_COOKIE_VARS) );

// Query the cache

if ($content = $cache->start($cache_id)) {
// Cache Hit

echo $content;
die();
}

// Cache Miss

// -- content producing code here --

// Store page into cache

echo $cache->end();
?>

With the Cache_Output class, it is easily possible to turn a dynamic, database-driven web application into a static one. This can drastically improve a site's performance.

Related Reading

PHP Pocket ReferencePHP Pocket Reference
By Rasmus Lerdorf
Table of Contents
Sample Section
Full Description
Read Online -- Safari

More and more web sites are using GZIP compression for their HTML content. This reduces the server's bandwidth, and thus the costs for the generated traffic. Furthermore, it increases the user experience for those using modem connections. Cache_OutputCompression extends the functionality of the Cache_Output class, as it caches the GZIP compressed version of the generated HTML to save the CPU time needed to compress the content.

Customized solutions

In this last section, I explain how the PEAR Cache framework can be used to develop customized caching solutions. As an example, I have chosen a class called MySQL_Query_Cache that caches the result sets of SELECT queries.

Let's start with the class's variables -- constructor and destructor. The constructor is used, as before with the Cache_Function and Cache_Output classes, to transport the cache container options. The destructor closes the MySQL connection and runs the cache's garbage collection, if needed.

<?php
require_once 'Cache.php';

class MySQL_Query_Cache extends Cache {
  var $connection = null;
  var $expires    = 3600;

  var $cursor = 0;
  var $result = array();

  function MySQL_Query_Cache($container  = 'file', 
      $container_options = array('cache_dir'=> '.', 
      'filename_prefix' => 'cache_'), $expires = 3600)
  {
    $this->Cache($container, $container_options);
    $this->expires = $expires;      
  }

  function _MySQL_Query_Cache() {
      if (is_resource($this->connection)) {
        mysql_close($this->connection);
      }

      $this->_Cache();
  }
}
?>

Before we come to the juicy part, where we actually perform and cache the query, we need some more helper functions.

<?php
function connect($hostname, $username, $password, $database) {
  $this->connection = mysql_connect($hostname, $username, $password) or trigger_error('Could not connect to database.', E_USER_ERROR);

  mysql_select_db($database, $this->connection) or trigger_error('Could not select database.', E_USER_ERROR);
}

function fetch_row() {
  if ($this->cursor < sizeof($this->result)) {
    return $this->result[$this->cursor++];
  } else {
    return false;
  }
}

function num_rows() {
  return sizeof($this->result);
}
?>

We already have ready the functionality needed to connect to a MySQL database, to fetch a row from a cached result set, and to get the number of rows in the current set. Let's see how we perform -- and cache -- a database query:

<?php
function query($query) {
  if (stristr($query, 'SELECT')) {
    // Compute unique cache identifier for this query

    $cache_id = md5($query);

    // Query the cache

    $this->result = $this->get($cache_id, 'mysql_query_cache');

    if ($this->result == NULL) {
      // Cache Miss

      $this->cursor = 0;
      $this->result = array();

      if (is_resource($this->connection)) {
        // Use mysql_unbuffered_query(), if available

        if (function_exists('mysql_unbuffered_query')) {$result = mysql_unbuffered_query($query, $this->connection);
        } else {$result = mysql_query($query, $this->connection);
        }

        // Fetch all result rows

        while ($row = mysql_fetch_assoc($result)) {$this->result[] = $row;
        }

        // Free MySQL Result Resource

        mysql_free_result($result);

        // Store result set in cache

        $this->save($cache_id, $this->result, $this->expires, 'mysql_query_cache');
      }
    }
  } else {
    // No SELECT query, don't cache it

    return mysql_query($query, $this->connection);
  }
}
?>

Example 3: The MySQL query cache in action

<?php
require_once 'MySQL_Query_Cache.php';

$cache = new MySQL_Query_Cache();
$cache->connect('hostname', 'username', 'password', 'database');
$cache->query('select * from table');

while ($row = $cache->fetch_row()) {
  echo '<p>';
  print_r($row);
  echo '</p>';
}
?>

With this information, you should be able to get started caching PHP web pages for most common applications.

Sebastian Bergmann is the author of a variety of PHP software projects such as PHPUnit and phpOpenTracker.


Return to the PHP DevCenter.


Comments on this article
Full Threads Oldest First

Showing messages 1 through 2 of 2.

  • PEAR Cache does not handle concurrency issues
    2001-12-26 19:25:08  mlemos [View]

    It seems that concurrency issues are not addressed in this article because PEAR Cache design did not made them mandatory.

    This means that you may have your cache files trashed by simultaneous accessses on which more than one attempts to update the cache contents. This may make PEAR Cache to file useless as it can't assure cache data integrity.

    PEAR Cache also can send the cached data to a database but this is just an academic type of container because in real world database access is much slower for this purpose than using local file system files. Usually you local file system based caches to avoid database accesses.

    Another point is that PEAR Cache db container uses SQL code specific to MySQL, despite PEAR DB can interface with other databases.
  • Obvious Question
    2001-12-15 11:23:26  tony_bibbs [View]

    How long do the queries get cached? Is the TTL configurable per query?


Recommended for You

Tagged Articles

Post to del.icio.us

This article has been tagged:

php

Articles that share the tag php:

Understanding MVC in PHP (477 tags)

The PHP Scalability Myth (123 tags)

The Dynamic Duo of PEAR::DB and Smarty (53 tags)

PHP Form Handling (43 tags)

Very Dynamic Web Interfaces (39 tags)

View All

cache

Articles that share the tag cache:

An AJAX Caching Strategy (13 tags)

Caching PHP Programs with PEAR (7 tags)

Eleven Metrics to Monitor for a Happy and Healthy Squid (3 tags)

Peering Squid Caches (3 tags)

Caching Dynamic Content with JSP 2.0 (2 tags)

View All

pear

Articles that share the tag pear:

The Dynamic Duo of PEAR::DB and Smarty (37 tags)

Programming eBay Web Services with PHP 5 and Services_Ebay (12 tags)

Three-Tier Development with PHP 5 (6 tags)

PHP's PEAR on Mac OS X (6 tags)

Caching PHP Programs with PEAR (6 tags)

View All

programming

Articles that share the tag programming:

Rolling with Ruby on Rails (1374 tags)

Very Dynamic Web Interfaces (279 tags)

Ajax on Rails (231 tags)

Understanding MVC in PHP (202 tags)

A Simpler Ajax Path (186 tags)

View All

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

Sign up today to receive special discounts,
product alerts, and news from O'Reilly.
Privacy Policy >
View Sample Newsletter >
  • Youtube
  • http://www.youtube.com/OreillyMedia
  • Twitter
  • Subscribe
  • View All RSS Feeds >
O'Reilly Media

800-889-8969 or 707-827-7019
Monday-Friday 7:30am-5pm PT
©2011, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
  • About O'Reilly
  • Academic Solutions
  • Contacts
  • Customer Service
  • Careers
  • Press Room
  • Privacy Policy
  • Terms of Service
  • Writing for O'Reilly
  • Community
  • Authors
  • Forums
  • Membership
  • Newsletters
  • RSS Feeds
  • User Groups
  • Partner Sites
  • makezine.com
  • makerfaire.com
  • craftzine.com
  • igniteshow.com
  • PayPal Developer Zone
  • O'Reilly Insights on Forbes.com