Skip to content

Update from webcast on Zend_Cache_Frontend_Class

Dear Reader,

In reading over the chat room log for my recent webcast, Zend Framework: Piece by Piece I noticed a question from my buddy Elazar about Zend_Cache_Frontend_Class. Thinking I had made a mistake, I reviewed the materials and the Zend_Cache_Frontend_Class documentation page so that I could do a quick update. The answer wasn’t nearly as simple as I thought.

Zend_Cache_Frontend_Class is not a proxy

My original thought, having never actually had the opportunity to use this front end, was that Zend_Cache_Frontend_Class acted as a proxy for the instantiated object and cached any results so that expensive methods would be cached and could be re-called repeatedly and the cached results returned.

Here’s my simple test case I wrote to prove this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class User {
    protected $firstName;
    protected $lastName;
    protected $pictures;
 
    public function formatName()
    {
        return $this->firstName . ' ' . $this->lastName;
    }
 
    public function __get($name) {
        return $this->$name;
    }
    public function __set($name, $value) {
        return $this->$name = $value;
    }
 
    public function getPictures()
    {
        $flickrApiKey='';
        if (empty($this->firstName) and empty($this->lastName)) {
            return array();
        }
        $flickr = new Zend_Service_Flickr($flickrApiKey);
        $results = $flickr->tagSearch($this->firstName.$this->lastName);
        $pictures = array();
        foreach($results as $result) {
            $pictures[] = array('thumbnail'=> $result->Thumbnail->uri,
                                    'title'    => $result->title);
        }
        return $pictures;
    }
 
}

This version worked fine when I instantiated an instance of the class by itself and called the method. However, following the advice from the manual page, I used this call to create my cache object.

1
2
3
4
5
6
7
8
$cache = Zend_Cache::factory('Class',
			     'File',
			     array(
				   'lifetime' => null, 
				   'cached_entity' => new User()),
			     array(
				   'cache_dir' => 'd:/personal/projects/pieces.local/data')
			     );

The cached entity is created when the cache is created. This works just fine
except that $cache is not, as it would seem, a proxy for User. You are able, as the manual shows, to call the methods from the object, pass in parameters and if the results already exist and have not expired, it will return the cached results transparently. This is very similar to how Zend_Cache_Frontend_Class operates on static methods. The failing here is that, it can only act as if it is a static method. The following code, will not work as expected; however, will not fail either.

1
2
$cache->firstName = 'Cal';
$cache->lastName = 'Evans';

If you now print_r($cache) you will see that $cache does indeed now have 2 new properties but they are not part of $cache->cached_entity, the class that was cached. $cache is not acting as a full proxy as the manual would insinuate but rather simply a proxy for the methods.

There are two potential solutions to this, an easy one and a hard one.

The Easy Solution

1
2
3
4
5
6
7
8
9
10
11
12
$o = new User();
$o->firstName = 'Cal';
$o->lastName = 'Evans';
 
$cache = Zend_Cache::factory('Class',
			     'File',
			     array(
				   'lifetime' => null, 
				   'cached_entity' => $o),
			     array(
				   'cache_dir' => 'd:/personal/projects/pieces.local/data')
			     );

Once the class properties have been populated, you can hand the instance to the Zend_Cache::factory and the method will work using the internal properties. The down side is, of course, you lose access to the instance of the class itself. Passing by reference does not work either, once the cache has it, it’s gone.

The Hard Solution

In researching this post, I came across an interesting blog post titled “A caching pattern for models” by Pascal Opitz. I won’t go into the details because it’s not an easy solution. Here is a quote from the post:

The initial thought behind this is that a model should be able to return calls either uncached or cached, without initializing some cache object every time. It should be easy to switch between the two calls, and the cache should be coming with the model object already.

It’s a very interesting solution but not one that will be easily integrated into existing applications. I do, however, recommend you reading it if you want caching to work seamlessly in your models.

Summary

I wasn’t thorough in my webinar so I hope this clear things up a bit. Zend_Cache_Frontend_Class is most useful with static methods and classes. It can use instantiated classes but not as a transparent proxy.

Sample Code

Zend_Cache_Frontend_Class Demo code. (Includes zf.phar)
To test for yourself, grab this file and unzip. It comes with zf.phar that I showed how to build in Lessons in Phar. If you have ext/phar installed, you should be good to go, otherwise, you need to change the include to your copy of the Zend Framework. Also, you will need a flickr account and API key to make this work.

Until next time,
I <3 |<
=C=

2 thoughts on “Update from webcast on Zend_Cache_Frontend_Class

  1. I use the propel orm and extended it’s query buIlder (Php5PeerBuilder.php) to automatically return the cache IF $config->cache_status == 1 && $model->_caching == 1. Caching status defaults to 1 in production and staging, but 0 in dev. Model caching defaults to 1 but is adjustable with getters & setters. This centralized solution is easy to bolt on after the fact.

Comments are closed.