Есть сайт, который состоит из элементов контент которых дергается из бд.
Для снижения нагрузки на сервер БД, можно результат запросов писать в кэш, при этом здесь мы рассмотрим реализацию файлового кэша.
логика работы такова.
прежде чем обратиться к базе с очередным селектом, смотрим, есть ли в специально отведенной папке под это дело файла, отвечающего за конкретно этот запрос. Если файл есть, то прочитать его, если нет, то послать запрос, и результат записать в кэш, чтобы не изобретать велосипед, данные в кеш пишутся сериализоваными.
в идеале это сводится к следующему:
$query='SELECT * FROM `table` ORDER BY id DESC LIMIT 1';
$rez=$cache->get('GET_LAST_POST',$query);
но, это требует от класса еще научится работать с БД, что непременно его усложнит.
поэтому вот модель попроще:
$query='SELECT * FROM `table` ORDER BY id DESC LIMIT 1';
$rez=$cache->is('GET_LAST_POST') ? $cache->get('GET_LAST_POST') : mysql_query($query);
$cache->put($rez);
Уже не так красиво, как в первом варианте, зато не требует от будущего класса функций сверх необходимых.
Теперь остановимся подробнее, на структуре класса занимающегося кэшированием.
Наш класс должен знать куда писать, он дожен уметь создавать перезаписывать и удалять файлы, подготавливать данные к помещению и изъятию из кэша.
вот так он выглядит у меня:
class Cache {
private $path=''; # путь до папки с кэшем
private $str=''; # имя файла кэша
private $isStr=false; #есть ли имя
private $isCache=false; #есть ли файл по этому имени
# устанавливаем путь
public function setPath($path){
$this->path=$path;
}
# передаем имя
public function setStr($str){
$str=trim($str);
if (strlen($str)<=2){
return false;
}else{
$this->str=$this->prepareStr($str);
$this->isStr=true;
$this->isCache=($this->isFile($this->str))?true:false;
return true;
}
}
# возвращаем сгенерированое имя, имя конкретного файла кэша
public function getStr(){
return $this->str;
}
# возвращаем кэш, если есть что
public function getCache(){
if ($this->isCache==true){
return file_get_contents($this->path.'/'.$this->str);
}else{
return '';
}
}
# есть ли кэш
public function isCache(){
return $this->isCache;
}
# записать в кэш
public function putToCache($str){
if ($this->isStr){
$file = fopen ($this->path.'/'.$this->str,'w');
if ( !$file )
{
$this->isCache=false;
return false;
}
else
{
fputs ( $file, $str);
}
fclose ($file);
if ($this->isFile($this->str)==true){
$this->isCache=true;
return true;
}else{
return false;
}
}else{
return false;
}
}
#очстить папку кэша
public function clearCache(){
if (empty($this->path) || !file_exists($this->path.'/')){return false;}
$dir = opendir ($this->path.'/');
while ( $file = readdir ($dir)){
if (( $file != ".") && ($file != "..") && strlen($file)==32)
{
if (is_file($this->path.'/'.$file)){$this->deleteFile($this->path.'/'.$file);}
}
}
closedir ($dir);
return true;
}
#физическое удаление файла
private function deleteFile($file){
//print $file;
unlink($file);
}
#есть ли файл кэша
private function isFile($file){
return (!empty($file) && file_exists($this->path.'/'.$file))?true:false;
}
#подготавливаем имя файла из переданных параметров
private function prepareStr($str){
return md5(strtolower($str));
}
}
вроде бы все возможные косяки были учтены, и код работает.
Живой пример использования класса:
include_once('/class/Cache.php');
$cache=new Cache;
$cache->setPath('/www/cache');
#cache_code
if(isset($cache) && $cache->setStr('GET_NEWS_'.$_GET['id']) && $cache->isCache()){
$aNews=unserialize($cache->getCache());
}
else{
$aNews=mysql_query('SELECT * FROM `news` WHERE `id`='.$_GET['id'].' LIMIT 1;');
if (isset($cache)){$cache->putToCache(serialize($aNews));}
}
#