PHP PEAR Cache_Lite

dev*_*ect 2 php pear memcached

你好。

由于我使用的是共享托管包,并且无法使用 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;
  }
}
?>
Run Code Online (Sandbox Code Playgroud)

这个我的小“缓存系统”工作得很好,正如我所看到的,PEAR Cache_Lite 的工作方式几乎相同,而且由于我不熟悉 pear 缓存系统,我想知道什么是更好、更安全、更快的解决方案在这两者之间使用,为什么?

非常感谢!!

irc*_*ell 5

就个人而言,我会为此使用一个库。编写缓存层看起来要困难得多。不是难到你做不到,但很难把所有的边缘情况和怪癖都排除在系统之外。您可以使用 Cache_Lite 之类的东西,但我建议使用更好的缓存层。其中有一些(独立的和框架出生的)。以下是一些:

  • Zend_Cache - 您可以独立使用它。但它的设计和测试也非常好......

  • Cache_Lite - 如果您只想要文件缓存。它重量轻,但也不是非常灵活(但这可能是您想要的)。

  • Kohana 的缓存。它相当灵活,但我不太确定与框架的其余部分分离会有多容易(没有经验)。

关于您的代码的一些评论:

  1. 我会使用不同的变量名。 函数中的名称对于它$file_existscache()作用来说非常糟糕。它应该是类似的东西$cache_results。使用语义来识别您的姓名。

  2. 我真的会把它包装在一个类中,这样你就可以更好地进行初始化。有些事情每个请求你只想做一次,所以没有必要每次都做(稍后会详细介绍)。

  3. 清除您的统计缓存!每个请求运行clearstatcache() 一次。其原因是,PHP可以缓存无效的统计信息,并返回错误信息file_existsfilemtime等等。但是它是相当昂贵的,所以我不会运行它超过每一次的请求......

  4. 根本不需要使用opendirinread()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);
    }
    
    Run Code Online (Sandbox Code Playgroud)