2

Given a class with some really expensive code, I want to avoid running that code when re-defining an instance.

Best explained with some pseudo-code:

$foo = new Foo('bar'); print $foo->eat_cpu_and_database_resources(); #=> 3.14159 $foo->store_in_cache(); #Uses an existing Memcached and/or caching to store serialized. #new thread, such as a new HTTP request. Could be days later. $bar = new Foo('bar'); print $foo->eat_cpu_and_database_resources(); #=> 3.14159 

The second $bar should re-initialize the earlier created instance $foo. Inside my actual class, I do several things on eat_cpu_and_database_resources(), which is named get_weighted_tags(): calculate a weighted tagcloud from values in $foo->tags. $foo->tags() was filled with expensive $foo->add_tag() calls. I would like to retrieve the prepared and filled instance from now on, from cache.

I have tried to simply fetch from (serialized) cache on __construct() and assign the retrieved instance to $this, which is not allowed in PHP:

 function __construct ($id) { if ($cached = $this->cache_get($id)) { $this = $cached } else { #initialize normally } } 

Is this a proper way? Or should I treat every instance unique and instead apply caching in the eat_cpu_and_database_resources() method, instead of caching the entire instance?

Is there a built-in way in PHP to revive old instances (in a new thread)?

4
  • Well, are you actually using a Cache, like memcached or APC? By #new thread you mean new request? Or do you just want to have the same instance during one request? Is the eat_cpu method the expensive one or is it the actual object creation? Can you make the pseudecode more concrete please? Commented Apr 15, 2011 at 10:07
  • 1
    Done. I want to stress that the caching is a (Drupal) caching system that is available already: it will cache on disk, memcached or in the database (serialized) depending on settings and such. The ins and outs of store_in_cache() don't really matter, just the fact that it will serialize and persistent store the current instance. Commented Apr 15, 2011 at 10:19
  • 1
    I'd try to implement some factory methods, like Foo_Factory::create, wich will first check your cache for a serialized object. If found: $result = unserialize(...your source...) and else create a new instance ($result = new Foo(...constructor args...)). Also hava look at __sleep/__wakeup, mabye those will help too, php.net/manual/en/language.oop5.magic.php Commented Apr 15, 2011 at 10:26
  • Foo_Factory::create was the missing piece. Thanks. Commented Apr 15, 2011 at 11:57

1 Answer 1

2

Depending on the size of Foo, you might want to cache the entire object in the cache store Drupal provides. If it's too big for that, see if it makes sense to just cache the result to the expensive method call(s).

If you want to unserialize an object from the PHP internal format, you have to use the corresponding unserialize method and might want to add the magic __wakeup method to do any post re-initializations:

The intended use of __wakeup is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.

Since you have to have the serialized string for that first, you might want to add some facilitiy to encapsulate this logic, like a Factory or Builder pattern or a dedicated FooCache.

Personally I find caching the method call the best option because there's no point in caching the whole object when it's really just the method call that's expensive. That will also save you any additional work checking whether there is a serialized string to start with or building a factory.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.