Mając już opracowany sposób zarządzania zapleczem cache w naszej aplikacji, czyli mamy menedżera cache, możemy przystąpić do jego szerokiego stosowania.
Ponieważ w większości przypadków cache zaczynamy stosować już po stworzeniu większości funkcjonalności, to należy postarać się, aby jego użycie nie wpływało negatywnie na jakość kodu. W tym celu można użyć wzorca projektowego cache’ującego proxy.

Cache proxy

Wzorzec ten polega na stworzeniu obiektu, który będzie „okalał” inny obiekt, którego metody mają zostać cache’owane. Przy korzystaniu z instancji obiektu objętego takim proxy każde wywołanie funkcji najpierw zostanie zweryfikowane pod względem posiadania już gotowego wyniku w pamięci podręcznej. Przykładowa implementacja takiego proxy może wyglądać następująco:

[php]
namespace DivanteCache;

use Manager as CacheManager;

class Proxy
{
protected $___coveredObjectInstance = null;
protected $___coveredObjectId = null;
protected $___cacheManager = null;

public function __construct($object, $id)
{
if (is_object($object)){
$this->___coveredObjectInstance = $object;
$this->___coveredObjectId = $id;
$this->___cacheManager = Manager::getInstance();
}
else
throw new Exception(‚Parameter $object is not valid object.’);
}

/**
* @param $method
* @param array $params
* @return mixed
*/
public function __call($method, array $params = array())
{
$cacheKey = $this->____calculateCacheKey($method, $params);

if (!$result = $this->___cacheManager->load($cacheKey)) {
$result = call_user_func_array(array($this->___coveredObjectInstance, $method), $params);
$this->___cacheManager->save($cacheKey, $result, $this->____calculateTTL($method));
}

return $result;
}

/**
* @param string $method
* @param mixed $params
* @return string
*/
protected function ____calculateCacheKey($method, $params)
{
// uproszczona implementacja – nie wszystkie parametry są serializowalne
$cacheKey = get_class($this->___coveredObjectInstance) . ‚.’ . $method . ‚<<‚. serialize($params);
return $cacheKey;
}

/**
* @param $method
* @return int
*/
protected function ____calculateTTL($method)
{
// obliczenie TTL, może być stałe dla danych klas lub pobierane z docblocka
//…
}
}
[/php]

Później użycie takiej implementacji może wyglądać jak poniżej:

[php]
$someObject = new SomeObject();
$cachedByProxy = new DivanteCacheProxy($someObject);

$cachedByProxy->someMethod();
[/php]

Jak widzimy, wywołanie metody someMethod klasy SomeObject najpierw będzie zweryfikowane przez metodę __call, czy nie istnieje odpowiedni wpis w cache.

Użycie tego wzorca projektowego w połączeniu np. ze definiowaniem parametrów dla cache w docblockach daje dużą kontrolę oraz transparentność z punktu widzenia samych cache’owanych obiektów.