Кэширование данных в PHP с помощью CitrusLib

Кэширование данных в PHP с помощью CitrusLib

Кэширование является мощным инструментом в борьбе с улучшением производительности веб-приложения. Без технологии кэширования, веб-серверу приходилось бы снова и снова генерировать новый ответ для клиента тем самым теряя в производительности приложения. Если у вас динамичный проект который требует использование базы данных и выполнение при каждом запросе огромного кода, то технологии кэширования помогут вам выиграть во времени выполнения кода. Если же ваш сайт написан на чистом HTML+CSS то использовать кэширование нету смысла.

В данном примере мы посмотрим как работает мой небольшой класс по кэшированию данных в файловой системе. Сохранять данные мы будем в обычных текстовых файлах. Класс не требует долгой и нужной установки, достаточно создать для него папку-хранилище для сохранения кэша и дать ей права 777.

>> Скачать библиотеку с примерами (Citruslib-phpCache.zip)

Данную библиотеку назвал Citrus. Посмотри ее исходный код:

<?php
define('DS', DIRECTORY_SEPARATOR);
class Citrus {
    
    public $storage = '';
    
    public function __construct($storage='') {
        if(!$storage) {
            // Путь не задан, указываем его по умолчанию
            $this->storage = __DIR__. DS . 'storage' . DS;
        } else {
            // Задан собсвенный путь к хранилищу
            $this->storage = $storage;
        }
       
        if(!is_writable($this->storage)) {
            die('Cache folder ('.$this->storage.') need to be 777 permissions');
        }
    }
    
    public function __destruct() {
        /*
         * Чистильщик старых кэш-файлов
         */
        $cached_files = glob($this->storage . '*');
        if(count($cached_files)) {
            foreach($cached_files as $filename) {
                if(!$this->is_actual($filename)) {
                    $this->delete($filename);
                }
            }
        }
    }
    
    public function save($cache_key, $source, $minutes=0) {
        /*
         * Сохранение кэш-файла
         */
        $cache_filename = md5($cache_key);
        $Open = fopen($this->storage . $cache_filename, 'w');
        $final_source = "TIME=". ($minutes * 60) ."\n". $source;
        fwrite($Open, $final_source);
        return $source;
    }
    
    public function has($cache_key) {
        /*
         * Проверка на существование и актуальность кэш-файла
         */
        $cache_filename = $this->storage . md5($cache_key);
        if(!file_exists($cache_filename)) {
            return False;
        }
         else {
             return $this->is_actual($cache_filename);
         }
    }
    
    public function view($cache_key, $source='', $time=0) {
        /*
         * Просмотр содержимоего кэш-файла с возможность пересохранить
         */
        $cache_filename = $this->storage . md5($cache_key);
        if($this->has($cache_key)) {
            $Source = file_get_contents($cache_filename);
            return preg_replace("#TIME=\d+\n#", '', $Source);
        }
         else {
             if(!$source) {
                 return $source;
             }
              else {
                  return $this->save($cache_key, $source, $time);
              }
         }
    }
    
    public function forget($cache_key) {
        /*
         * Удаление кэш-файла по его ключу
         */
        $cache_filename = $this->storage . md5($cache_key);
        return $this->delete($cache_filename);
    }
    
    private function delete($filename) {
        /*
         * Удаление кэш-файла через его путь
         */
        if(file_exists($filename)) {
            return unlink($filename);
        }
         else {
             return True;
         }
    }
    
    public function is_actual($filename) {
        /*
         * Проверка на актуальность кэш-файла
         */
        $Source = file_get_contents($filename);
        preg_match("#TIME=(\d+)#", $Source, $matches);
        if( (filemtime($filename) + $matches[1]) < time() ) {
            $this->delete($filename);
            return False;
        }
         else {
            return True;
         }
    }
    
}
?>

Установка

Можно создать папку storage рядом с PHP-файлом класса или указать свой путь к хранилищу вовремя инициализации класса. Не забудьте дать папке права 777.

Примеры

Попробуем сохранить некоторые данные в кэш на 5 минут.

<?php
header('Content-Type: text/html; charset=utf-8');
include_once('Citrus.php');
/*
 * Указать новый путь для сохранения кэша можно таким образом:
 * $Citrus = new Citrus('/var/www/store/'); // <- Linux
 * $Citrus = new Citrus('D:\\AppServ\www\storage\'); // <- Windows
 */
$Citrus = new Citrus;
if(!$Citrus->has('time')) {
    echo "Сохраняем данные в кэш.<br>";
    echo $Citrus->save('time', 'Я был сохранен ' . date('Y-m-d H:i:s') ,  5);
}
 else {
     echo 'Читаем из кэша<br>';
     echo $Citrus->view('time');
     echo '<br>Сейчас: '.date('Y-m-d H:i:s').'<br>';
 }
?>

Результат работы:

Читаем из кэша
Я был сохранен 2013-03-11 20:46:49
Сейчас: 2013-03-11 20:50:14

Хочу заметить, что метод $Citrus->view() может сам сохранять новые данные если они потеряли актуальность или более недоступны. Таким образом можно более не пользоваться проверкой $Citrus->has():

<?php
echo $Citrus->view('from_view', 'Я сразу из обзорщика', 10);
?>
Если кэш с ключем from_view существует и он актуален то выводится его содержимое. Если такого файла не существует или потерял свою актуальность новые данные будут записаны в соответствии со вторым и третьим параметром.

Удаление кэша

Ну, если уже создали то нужно как-то их удалять. Для удаления файлов кэша, мы воспользуемся методом $Citrus->forget() и передадим ему ключ кэша.
<?php
$Citrus->forget('my_key');
?>
Третий параметр методом $Citrus->save() и $Citrus->view() является время жизни кэша в минутах!

Если есть какие либо замечания по данной статье прошу напишите в комментариях.

Вопросы к читателям блога

- Какие методики кэширования используете вы?

- Какие функции вы хотели бы увидеть в CitrusLib в будущем?

11 марта 2013, 22:29 PHPmowshon6245RSS
Комментариев: 1
  1. // Путь не задан, указываем его по умолчанию

    $this->storage = (rtrim($_SERVER['DOCUMENT_ROOT'], DS) . DS . "cache" . DS);

    так проше и удобней

Оставьте комментарий!

Комментарий будет опубликован после проверки

Имя и сайт используются только при регистрации

(обязательно)