PHP PEAR Cache_Lite - PullRequest
       21

PHP PEAR Cache_Lite

2 голосов
/ 01 марта 2011

HI.

Поскольку я использую пакет общего хостинга, и я не могу использовать PECL Memcache, я был бы признателен за несколько советов относительно моих собственных сомнений между использованием моей собственной маленькой системы кэширования или системой PEAR Cache_Lite.

Итак, вот мои функции:

<?php

//this one create a simple .txt file named by unique query_key string generated width e.g $file_name=md5("SELECT * FROM table"); content of that file is serialized value of mysql return

function write($query_key,$result)
{
  global $config;
  $new_file_name=md5($query_key);
  $result_to_write=serialize($result);  
  if($handle=opendir($config['cache_dir'])) 
  {
    $f=fopen($config['cache_dir'].$new_file_name.'.txt','w+');
    fwrite($f,$result_to_write);        
    fclose($f);
    closedir($handle);
  }
}

// this one reads content of file (serialized mysql return of unique query_key) if timeout hes not expired, and if it is it return false

function read($query_key,$timeout)
{
  global $config;
  $file_name=md5($query_key);
  if($handle=opendir($config['cache_dir'])) 
  {
    if(file_exists($config['cache_dir'].$file_name.'.txt'))
    {
      $last_accessed=filemtime($config['cache_dir'].$file_name.'.txt');
      $now=time();
      if(($now-$last_accessed)<$timeout)
      {
        $file=fopen($config['cache_dir'].$file_name.'.txt','rb');
        $f=fread($file,filesize($config['cache_dir'].$file_name.'.txt'));
        $array=unserialize($f);
        fclose($file);  
        closedir($handle);
      }else{ return FALSE; }
    }else{ return FALSE; }
  }
  if(!empty($array)) return $array;
  else return FALSE;
}

//and finally this one which is used when executing query, so it has timeout in seconds, if file (cached result) exists, and timeout has not expired, it returnt cached data , or it reads from database returns new result,and cache new result by writing new file

function cache($query)
{
  $timeout=600;
  $file_exists=read($query,$timeout);
  if($file_exists)
  {
    return $file_exists;
  }else{
    $result=get_rows($query);
    write($query,$result);
    return $result;
  }
}
?>

Эта моя маленькая "система кэширования" работает очень хорошо, и, как я вижу, PEAR Cache_Lite работает почти так же, как и яне знакомы с системой кэширования груш, я хотел бы знать, что является лучшим, более безопасным и быстрым решением для использования между этими двумя и почему ??

Спасибо большое !!

1 Ответ

4 голосов
/ 01 марта 2011

Лично я бы использовал библиотеку для этого. Написание кеширующего слоя намного сложнее, чем кажется. Это не так сложно, что вы не можете сделать это, но трудно вывести все крайние случаи и причуды из системы. Вы можете использовать что-то вроде Cache_Lite, но я бы предложил лучший уровень кэширования. Есть несколько из них (как автономные, так и фреймворк). Вот некоторые из них:

  • Zend_Cache - Вы можете использовать это автономно. Но он также довольно хорошо спроектирован и протестирован ...

  • Cache_Lite - если вы хотите только кэширование файлов. Это легкий вес, но не очень гибкий (но это может быть то, что вы хотите).

  • Кеш Коханы . Он довольно гибкий, но я не уверен, насколько легко будет отделиться от остальной части фреймворка (без опыта работы с ним).

Несколько комментариев о вашем коде:

  1. Я бы использовал разные имена переменных. $file_exists в функции cache() - действительно плохое название для того, что она делает. Это должно быть что-то вроде $cache_results. Используйте семантическое значение для идентификации ваших имен.

  2. Я бы действительно обернул это в классе, чтобы вы могли лучше выполнить инициализацию. Есть некоторые вещи, которые вы хотите делать только один раз для каждого запроса, поэтому нет необходимости делать это каждый раз (подробнее об этом чуть позже).

  3. Очистите кеш статистики! Выполните clearstatcache() один раз для запроса. Причина в том, что PHP может кэшировать неверную статистическую информацию и возвращать неверную информацию для file_exists, filemtime и т. Д. Но это довольно дорого, поэтому я бы не стал запускать его более одного раза за запрос ...

  4. Нет необходимости использовать opendir вообще в read() или write(). Если вы хотите убедиться, что каталог существует, просто наберите is_dir($dir). Прямо сейчас вы открываете ручку и ничего не делаете с ней.

  5. У вас есть утечка ресурсов в read() и write(), где есть пути, где вы открываете каталог, но не закрываете его. Хотя в большинстве случаев это не будет иметь большого значения, закройте ваши ресурсы должным образом. (еще лучше, полностью исключить звонки).

  6. Не используйте fopen(); fwrite(); fclose(); для этого типа операции. Вы можете снимать себя, если во время записи в файл поступит другой запрос (что приведет к частичному чтению). Вместо этого используйте file_put_contents($filename, $data, LOCK_EX); для записи. Это в основном атомное (не совсем, но достаточно близко для ваших целей). И я бы заблокировал файл перед чтением в read():

    $file=fopen($config['cache_dir'].$file_name.'.txt','rb');
    if (flock($file, LOCK_SH)) {
        $f=fread($file,filesize($config['cache_dir'].$file_name.'.txt'));
        flock($file, LOCK_UN);
    }
    
...