Cachowanie wyników zapytania przyda się zawsze tam, gdzie dane nie zmieniają się zbyt szybko. Statyczny wynik przechowywany w plikowym cache będzie również pobierany przez aplikację szybciej niż wykonanie ponownie zapytania na bazie. Jest to też prawdziwe dla wywołań metod w WebService. Problem jaki się pojawia, to jak rozsądnie cachować te wyniki?
Wróćmy na chwilę do SQL. Prędzej czy później zapytanie SQL to prosty tekst. Z tego tekstu zawsze łatwo można uzyskać skrót, który potem służy do identyfikacji pliku z cache wyniku. Takie rozwiązanie całkiem nieźle się sprawdza. Nie ma znaczenia co wrzucamy do Zend_Cache, bo zawsze podlega serializacji. Problemem jest tylko wyznaczenie unikalnej nazwy dobrze identyfikującej zapytanie i używanie tego w sposób globalny. Dlatego też osobiście używam takiego kodu:
queryCache($query, $bind, $lifetime) {
$zend_cache = static::initCache($lifetime);
$name = 'query_' . md5($query . serialize($bind));
$wynik = $zend_cache->load($name);
if($wynik === false) {
if (empty($bind)) {
$wynik = self::getDb()->query($query)->fetchAll();
} else {
$wynik = self::getDb()->query($query, $bind)->fetchAll();
}
$zend_cache->save($wynik, $name);
}
return $wynik;
}
Jak widać nazwa wyznaczana jest z zapytania i tablicy parametrów. To samo zapytanie, z tymi samymi parametrami daje taką samą nazwę w cache. Jak więc łatwo i uniwersalnie budować statyki w cache dla wywołania metod klasy klienta WS?
Poniżej prezentuję swoje rozwiązanie:
public static function queryCallable($callable, $parameters = array(), $lifetime = 86400, ) {
$zend_cache = static::initCache($lifetime);
$name = 'call_' . md5(serialize($callable) . serialize($parameters));
$wynik = $zend_cache->load($name);
if($wynik === false) {
$wynik = call_user_func_array($callable, $parameters);
$zend_cache->save($wynik, $name);
}
return $wynik;
}
W tym przypadku nazwa jest generowana na podstawie callable i tablicy parametrów. Klient WS realizuje wzorzec Singleton, dzięki czemu z łatwością można cachować każde wywołanie tej samej metody dla tych samych parametrów w całej aplikacji i co ważne można to zrobić w sposób stosunkowo przezroczysty. Oczywiście zamiast napisać:
$client = WSClient::getInstance(); $data = $client->callMethod($param);
Trzeba napisać:
$data = CacheFactory::queryCallable(array(WSClient::getInstance(), 'callMethod'), array($param));Uzyskany wynik będzie identyczny. Jedyny problem jest taki, że budując callable nie możemy oprzeć się na pomocy IDE. Utrudnione jest też wyszukiwanie wszystkich odwołań do metody w callable co nieco utrudnia refaktoryzację.

Brak komentarzy:
Prześlij komentarz