Cache genérico simples usando o método php magic __call

Mesmo se houver soluções cada vez mais escaláveis ​​e de alto desempenho para acessar e processar dados, você precisa implementar pequenos cachings de vez em quando.

Este exemplo mostra uma implementação fácil e genérica para um mecanismo de cache simples de adicionar e sem interrupções usando o __callmétodo php .

AVISO LEGAL

O exemplo nunca foi produtivo e deve apenas explicar a ideia. Neste exemplo, o memcache é usado, mas não há dependência direta do memcache e o método também pode ser implementado com todas as outras tecnologias de cache. O memcache neste código é mostrado como algum Service Facade com um get()e um set()método, porque o exemplo não deve mostrar, como fazer uma implementação de memcache.

A ideia

A ideia principal é que o resultado de uma função pode ser armazenado com uma construção de chave de seus atributos. É claro que isso não funcionará em todas as situações. por exemplo, se houver dependências de método internas que não estão incluídas na lista de atributos. (tempo, etc), mas funcionará em muitos casos.

Por exemplo, se você tiver um UserServicecom um método, getUser(id)pode facilmente herdar dele AbstractServicee chamar cache_getUser(id)para obter resultados armazenados em cache.

O método mágico é usado aqui como um interceptor que é disparado com um prefixo específico (neste caso ) e despacha entre a implementação original e o resultado do cache. Assim, o método será disparado e tomará o atributo e o serializará e construirá um MD5 junto com o nome do método (em situações diferentes, você deve adicionar o nome da classe, o nome do método e talvez o nome do pacote para evitar obter resultados de outro contexto). a chave para identificar o resultado certo. agora você pode verificar no cache se há um resultado válido. Caso contrário, basta chamar o método original, armazenar o resultado com a chave no cache e retornar o resultado. __call()"cache_"
__callid

Um problema é que não há invalidação do cache, então, depois que um resultado é armazenado no cache, o método retornará apenas o primeiro resultado armazenado. Para resolver esse problema, você pode definir algumas regras para invalidar externamente. Por exemplo, no memcache, você pode manipulá-lo para definir um tempo de expiração global para declarar por quanto tempo os resultados em cache serão armazenados no cache.

Então essa é a ideia. Por favor me diga, se você gosta.

aqui o código:

class AbstractService {
public static $CACHEPREFIX = 'cache_';
public function __call($methodName, $args) {
//checks first if the methodname includes the right prefix
if (strpos($methodName, AbstractService::$CACHEPREFIX) === 0) {

// here we have to build the original Methodname
$methodName
= substr($methodName, strlen(AbstractService::$CACHEPREFIX));

/*
* We build the cacheHash from the methodName & the method arguments

* Attention!! if you use this Impementation in different classes,

* you have to add the classname too.

*/

$cacheHash
= $this->buildCacheHash($methodName, $args);

if (method_exists($this, $methodName)) {

/*
* here we use our $cacheHash to fetch the result from a

* MemcacheServie

*/

$cacheResult
= MemcacheService::getInstance()->get($cacheHash);

// check if there is an Result
if ($cacheResult == true) {
return $cacheResult;
} else {

/*
* if there is no valid result, we have to call the original method

* to get the result, write the result to our cache System and

* return the result

*/

$result
= call_user_func_array(array($this, $methodName), $args);
MemcacheService::getInstance()->set($cacheHash, $result);

return $result;
}
}
}
/*
* the __call function will only be called, if no other methodname .

* will match thats why we can throw an exception here.

*/

throw new Exception('Method ' . $methodName . ' not found');
}

/**
* method to build an hashkey for

* @ param string $methodName Name of the called method

* @ param array $args Arguments of the Method call

* @ return string MD5 of the methodName and the serialized Arguments

*/

public function buildCacheHash($methodName, $args) {
return md5($methodName . serialize($args));
}
}