Criando um sistema de cache no PHP

“Cache” é uma forma de armazenar um valor para um consulta futura mais rápida. Com o cache conseguimos otimizar o carregamento dos sites e de suas informações.

Suponhamos que você tenha um site que faça uma consulta em um tabela do banco de dados que possua 3.000.000 registros e essa consulta demore mais de 30 segundos (acredite, isso acontece). Com o cache você pode reduzir esse tempo em alguns segundos.

Cachear uma informação significa salvá-la em algum lugar (seja em um arquivo ou diretamente na memória RAM do servidor) para depois poder consultar essa informação sem ter que obtê-la da forma mais demorada (no exemplo a cima, com a consulta ao banco de dados).

Vamos criar aqui uma classe que servirá para armazenar qualquer tipo de texto, variável, número inteiro, resultado SQL e etc.

Para começar, começamos criando uma classe vazia:

01
< ?php 02 03 /** 04 * Sistema de cache 05 * 06 * @author Thiago Belem
07
* @link http://blog.thiagobelem.net/
08
*/
09
class Cache {
10

11
}
12

13
?>
Agora vamos adicionar alguns atributos que serão usados pelo sistema de cache:

01
/**
02
* Tempo padrão de cache
03
*
04
* @var string
05
*/
06
private static $time = ‘5 minutes’;
07

08
/**
09
* Local onde o cache será salvo
10
*
11
* Definido pelo construtor
12
*
13
* @var string
14
*/
15
private $folder;
O atributo $time define por quanto tempo as informações ficarão salvas no cache, tempo esse que poderá ser mudado para cada valor salvo (veremos mais a diante).

Agora vamos criar um método chamado setFolder() que servirá para definir o local onde os arquivos de cache serão salvos:

01
/**
02
* Define onde os arquivos de cache serão salvos
03
*
04
* Irá verificar se a pasta existe e pode ser escrita, caso contrário
05
* uma mensagem de erro será exibida
06
*
07
* @param string $folder Local para salvar os arquivos de cache (opcional)
08
*
09
* @return void
10
*/
11
protected function setFolder($folder) {
12
// Se a pasta existir, for uma pasta e puder ser escrita
13
if (file_exists($folder) && is_dir($folder) && is_writable($folder)) {
14
$this->folder = $folder;
15
} else {
16
trigger_error(‘Não foi possível acessar a pasta de cache’, E_USER_ERROR);
17
}
18
}
Esse método recebe o caminho (pasta) onde os arquivos serão criados e, após verificar se o caminho existe, é um diretório e pode ser manipulado, ele define um atributo com o caminho passado. Caso ele não consiga localizar a pasta ou não seja possível escrever nela, um erro será gerado.

Com esse método criado, podemos criar um construtor para essa classe com o seguinte código:

01
/**
02
* Construtor
03
*
04
* Inicializa a classe e permite a definição de onde os arquivos
05
* serão salvos. Se o parâmetro $folder for ignorado o local dos
06
* arquivos temporários do sistema operacional será usado
07
*
08
* @uses Cache::setFolder() Para definir o local dos arquivos de cache
09
*
10
* @param string $folder Local para salvar os arquivos de cache (opcional)
11
*
12
* @return void
13
*/
14
public function __construct($folder = null) {
15
$this->setFolder(!is_null($folder) ? $folder : sys_get_temp_dir());
16
}
O construtor será chamado sempre que instanciarmos a classe Cache e, como você pode ver, ele recebe um parâmetro (opcional) onde podemos definir o local onde os arquivos serão criados… Se não passarmos nenhum parâmetro para ele o mesmo irá usar o local de arquivos temporários definido pelo seu sistema operacional.

Agora que já conseguimos definir o local onde os caches serão salvos, vamos criar o método que irá gerar o nome dos arquivos de cache:

01
/**
02
* Gera o local do arquivo de cache baseado na chave passada
03
*
04
* @param string $key Uma chave para identificar o arquivo
05
*
06
* @return string Local do arquivo de cache
07
*/
08
protected function generateFileLocation($key) {
09
return $this->folder . DIRECTORY_SEPARATOR . sha1($key) . ‘.tmp’;
10
}
E o método que irá criar o arquivo de cache propriamente dito:

01
/**
02
* Cria um arquivo de cache
03
*
04
* @uses Cache::generateFileLocation() para gerar o local do arquivo de cache
05
*
06
* @param string $key Uma chave para identificar o arquivo
07
* @param string $content Conteúdo do arquivo de cache
08
*
09
* @return boolean Se o arquivo foi criado
10
*/
11
protected function createCacheFile($key, $content) {
12
// Gera o nome do arquivo
13
$filename = $this->generateFileLocation($key);
14

15
// Cria o arquivo com o conteúdo
16
return file_put_contents($filename, $content)
17
OR trigger_error(‘Não foi possível criar o arquivo de cache’, E_USER_ERROR);
18
}
O nosso sistema está quase pronto.. Já podemos criar arquivos de cache na pasta de cache, precisamos então criar dois métodos: um para salvar um valor no cache (seja ele uma string, número, resultado SQL e etc.) e outro pra ler esse valor do cache.

Primeiro o método que salva um valor no cache:

01
/**
02
* Salva um valor no cache
03
*
04
* @uses Cache::createCacheFile() para criar o arquivo com o cache
05
*
06
* @param string $key Uma chave para identificar o valor cacheado
07
* @param mixed $content Conteúdo/variável a ser salvo(a) no cache
08
* @param string $time Quanto tempo até o cache expirar (opcional)
09
*
10
* @return boolean Se o cache foi salvo
11
*/
12
public function save($key, $content, $time = null) {
13
$time = strtotime(!is_null($time) ? $time : self::$time);
14

15
$content = serialize(array(
16
‘expires’ => $time,
17
‘content’ => $content));
18

19
return $this->createCacheFile($key, $content);
20
}
E agora o método para ler esse valor do cache:

01
/**
02
* Salva um valor do cache
03
*
04
* @uses Cache::generateFileLocation() para gerar o local do arquivo de cache
05
*
06
* @param string $key Uma chave para identificar o valor cacheado
07
*
08
* @return mixed Se o cache foi encontrado retorna o seu valor, caso contrário retorna NULL
09
*/
10
public function read($key) {
11
$filename = $this->generateFileLocation($key);
12
if (file_exists($filename) && is_readable($filename)) {
13
$cache = unserialize(file_get_contents($filename));
14
if ($cache[‘expires’] > time()) {
15
return $cache[‘content’];
16
} else {
17
unlink($filename);
18
}
19
}
20
return null;
21
}
Se você reparar, esse último método irá excluir o arquivo de cache caso ele tenha expirado.

Usando o sistema de cache

Veja um exemplo de uso do sistema de cache onde primeiro verificamos se há um valor armazenado no cache e, se não houver, geramos o valor novamente e salvamos ele no cache para futuras verificações:

01
// Verifica se a frase já está no cache
02
$cache = new Cache();
03
$frase = $cache->read(‘frase-dia’);
04
// Se não houver frase no cache ou já tiver expirado
05
if (!$frase) {
06
// Cria uma nova frase e salva-a no cache por 30s
07
$frase = ‘CALMA! O sábio jamais se aborrece (‘. date(‘H:i:s’) .’)’;
08
$cache->save(‘frase-dia’, $frase, ’30 seconds’);
09
}
10
echo “

{$frase}

“;
Veja o código-fonte completo da classe: http://pastebin.com/p4m0CpwH

Um grande abraço e até a próxima! 🙂
http://blog.thiagobelem.net/criando-um-sistema-de-cache-no-php/

Deixe um comentário