Home arrow PHP arrow Swapping Cache Back-End at Runtime in PHP

Swapping Cache Back-End at Runtime in PHP

While the pattern is not as popular as other well-known contenders, like Singleton, Factory and Composite, “Plug-in” is a powerful structural paradigm. It permits developers to create extensible software systems by means of a clever combination of Composition and interfaces. By "interfaces," I mean native ones, or defined in the form of abstract classes.

TABLE OF CONTENTS:
  1. Swapping Cache Back-End at Runtime in PHP
  2. Caching opcode in the server
By: Alejandro Gervasio
Rating: starstarstarstarstar / 2
February 07, 2011

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

Thanks to the pattern's benefits, it’s possible to implement it in PHP and develop applications that can be extended without having to appeal directly to Inheritance. In keeping with this idea, in preceding parts of this series I demonstrated how to take advantage of the pattern’s functionality and create a couple of “pluggable” applications.

The first of these applications was pretty contrived, as it could only display different types of “renderable” objects on screen, including a few HTML widgets and some JavaScript boxes. The second one, however, presented a much more realistic scenario, since it could cache data by using either a server-side cache backend (which was a basic APC wrapper) or a client-side one, in this case composed of a simple proxy for the local storage feature packaged with HTML5.

With these cache backends already up and running, the next (and last) step we must take is to put them to work in a concrete example. In this way you'll see how easy it is to swap them at runtime, in accordance with the specific needs of client code. So, in this final chapter of the series I’m going to set up the example, thus finishing this humble educational journal through the “Plug-in” pattern in PHP. 

Review: the previous cache system

Since my goal here is to demonstrate that the caching system developed in previous tutorials of the series is really capable of plugging into different cache back-ends without having to modify the client code that consumes it, it’d be helpful to review the classes (and the interface) that make up the system. This way, you can recall the role that each of them plays in this context.

Having said that, first here’s the interface that defines the contract that must be implemented by any concrete cache backend:

(Cache/Cacheable.php)

<?php

namespace Cache;

interface Cacheable
{
 public function set($key, $data);
 public function get($key);
 public function delete($key);
 public function clear();     
}

As you’ll surely agree, the methods declared by the “Cacheable” interface are extremely intuitive, right? So move on and look at the following two concrete classes, which implement the two cache back-ends mentioned in the introduction. Here they are:

(Cache/ApcCache.php)

<?php

namespace Cache;

class ApcCache implements Cacheable
{
    /**
     * Save data to the cache
     */
    public function set($key, $data)
    {
        if (!apc_store($key, $data)) {
            throw new ApcCacheException('Error saving data with the key ' . $key . ' to the cache.');
        }
        return $this;
    }
   
    /**
     * Get the specified data from the cache
     */
    public function get($key)
    {
        if ($this->exists($key)) {
            if (!$data = apc_fetch($key)) {
                throw new ApcCacheException('Error fetching data with the key ' . $key . ' from the cache.');
            }
            return $data;
        }
        return null;
    }
   
    /**
     * Delete the specified data from the cache
     */
    public function delete($key)
    {
        if ($this->exists($key)) {
            if (!apc_delete($key)) {
                throw new ApcCacheException('Error deleting data with the key ' . $key . ' from the cache.');
            }
        }
        return $this;
    }
   
    /**
     * Check if the specified cache key exists
     */
    public function exists($key)
    {
        return apc_exists($key);
    }
   
    /**
     * Clear the cache
     */
    public function clear($cacheType = 'user')
    {
        return apc_clear_cache($cacheType);
    }       
}

 

(Cache/ApcCacheException.php)

<?php

namespace Cache;

class ApcCacheException extends Exception{}

 

(Cache/LocalCache.php)

<?php

namespace Cache;

class LocalCache implements Cacheable
{
    /**
     * Constructor (defines a basic set of local storage JavaScript functions)
     */
    public function __construct()
    {
        $js = <<<JAVASCRIPT
        <script>
        if ('localStorage' in window && window['localStorage'] !== null) {
            function set(key, data) {
                localStorage.setItem(key, data);
            }
            function get(key) {
                return localStorage.getItem(key);
            }
            function remove(key) {
                localStorage.removeItem(key);
            }
            function clear() {
                localStorage.clear();
            }
        }  
        </script>n
JAVASCRIPT;
        echo $js;
    }
   
    /**
     * Save an item to the local storage
     */
    public function set($key, $data)
    {
        if (!is_string($key) || !is_string($data)) {
            throw new LocalCacheException('The supplied key and data for the set() method must be strings.');  
        }  
        echo '<script>set('' . $key . '',' . ''' . $data . '');</script>' . "n";
        return $this;
    }
   
    /**
     * Get an item from the local storage (basic implementation)
     */
    public function get($key)
    {
        if (!is_string($key)) {
            throw new LocalCacheException('The supplied key for the get() method must be a string.'); 
        }
        echo '<script>get('' . $key . '');</script>' . "n";
    }
   
    /**
     * Remove an item from the local storage
     */
    public function delete($key)
    {
        if (!is_string($key)) {
            throw new LocalCacheException('The supplied key for the delete() method must be a string.');     
        }
        echo '<script>remove('' . $key . '');</script>' . "n";
    }
   
    /**
     * Clear the local storage
     */
    public function clear()
    {
        echo '<script>clear();</script>' . "n";
    }             
}

 

(Cache/LocalCacheException.php)

<?php

namespace Cache;

class LocalCacheException extends Exception{}

Although the above cache classes have already been discussed in depth, it’s worth briefly describing what they do, for the sake of completeness. The first one caches opcode via the popular APC PHP extension, while the second one is nothing but a simple wrapper for the local storage mechanism provided by HTML5. Now, do you remember how these cache backends do their thing? Good.

Finally, here’s the client class that consumes the existing back-ends through a dead simple API. Check it out:

(Cache/CacheHandler.php)

<?php

namespace Cache;

class CacheHandler
{
    protected $_cache;
   
    /**
     * Constructor
     */
    public function __construct(Cacheable $cache)
    {
        $this->_cache = $cache;
    }
   
    /**
     * Add the specified data to the cache
     */
    public function set($key, $data)
    {
        return $this->_cache->set($key, $data);
    }
   
    /**
     * Get the specified data from the cache
     */
    public function get($key)
    {
        return $this->_cache->get($key);
    }
   
    /**
     * Delete the specified data from the cache
     */
    public function delete($key)
    {
        $this->_cache->delete($key);
    }         
}

If someone asked for my opinion of the above “CacheHandler” class, I’d have to say that its implementation isn’t very impressive. However, first impressions are not always a programmer’s best friends. But why? Well, if you look more closely into the class, you’ll realize that it accepts an object of type “Cacheable” through its constructor, and that this object is stored as a protected property.

Even though this doesn’t seem to a big thing, this is in fact the nitty-gritty of the “Plug-in” pattern! Effectively, by taking any “cacheable” object, the class can be easily fed multiple cache backends, aside from the ones defined above. This means it offers a flexible schema that can be easily expanded without modifying its original implementation.

Of course, the best way to prove that this sample cache system is that flexible is by example. To fit this requirement, in the following section I’m going to create one, which will make use of the earlier “Apc” class to cache some trivial data in the server.

To see how this example will be created, click on the link below and keep reading.



 
 
>>> More PHP Articles          >>> More By Alejandro Gervasio
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: