Cache de variáveis no PHP (Parte 2)
Na primeira parte desta série tratei da utilização da
palavra-chave static como forma de manter uma variável
PHP em cache. No exemplo dado, mantinha-se a tabela
“role” completa em cache (de fato apenas os campos “id”
e “name” eram mantidos, mas todas demais colunas da tabela
poderiam ter sido mantidas em cache).
Minha tabela “roles” possuirá, no máximo, em torno de 20 registros, e por isso um cache completo da tabela não foi problemático. Mas pode ser interessante realizar o cache de tabelas maiores, com muitos milhares de registros, por exemplo. E aí entra a técnica que a partir de agora chamarei de “cache preguiçoso”.
A idéia do cache preguiçoso é a seguinte: você sabe que terá
de carregar para a variável em cache (no nosso exemplo, $roles)
um grande número de registros, mas não sabe de antemão
quais são. Como carregar todos os registros de uma única vez
pode levar muito tempo e/ou consumir muita memória, podemos acessar
o banco apenas quando for necessário, sob demanda. Confira
o exemplo a seguir.
function get_role_id($name) {
global $db;
static $roles;
if (empty($roles)) {
$roles = array(); // inicializa o cache
}
if (array_key_exists($name, $roles)) {
print "NAO acessei o BD...\n";
$role_id = $roles[$name]; // cache nao eh atualizado
}
else if ($role_id = $db->get_role_id_from_name($name)) {
print "Acessei o BD...\n";
$roles[$name] = $role_id; // coloca mais um valor no cache
}
else {
$role_id = null;
}
return $role_id;
}
A implementação do cache preguiçoso é bastante simples. Na primeira vez
que a função é chamada o cache ($roles) é inicializado. Nas chamadas
subseqüentes verifica-se se $roles possui um valor associado à chave
que chega como parâmetro. Nas primeiras chamadas da função é natural
que as chaves ainda não existam, e o banco é acessado (através do
objeto $bd) para recuperar o registro em questão.
Quando uma chave que já foi recuperada do banco é solicitada novamente, então não é mais preciso acessar o banco de dados (ela está no cache!). O programa abaixo utiliza essa função e ilustra seu funcionamento.
print " id do papel 'admin' = " . get_role_id('admin')."\n";
print " id do papel 'editor' = " . get_role_id('editor')."\n";
print " id do papel 'guest' = " . get_role_id('guest')."\n";
print " id do papel 'admin' = " . get_role_id('admin')."\n";
print " id do papel 'editor' = " . get_role_id('editor')."\n";
print " id do papel 'guest' = " . get_role_id('guest')."\n";
print " id do papel 'writer' = " . get_role_id('writer')."\n";
A saída do programa:
Acessei o BD...
id do papel 'admin' = 1
Acessei o BD...
id do papel 'editor' = 2
Acessei o BD...
id do papel 'guest' = 4
NAO acessei o BD...
id do papel 'admin' = 1
NAO acessei o BD...
id do papel 'editor' = 2
NAO acessei o BD...
id do papel 'guest' = 4
Acessei o BD...
id do papel 'writer' = 3