PHP緩存實現

  1. <?php  
  2. class  CacheException  extends  Exception {}  
  3. /**  
  4.  * 緩存抽象類  
  5.  */   
  6. abstract   class  Cache_Abstract {  
  7.     /**  
  8.      * 讀緩存變量  
  9.      *  
  10.      * @param string $key 緩存下標  
  11.      * @return mixed  
  12.      */   
  13.     abstract   public   function  fetch( $key );  
  14.       
  15.     /**  
  16.      * 緩存變量  
  17.      *  
  18.      * @param string $key 緩存變量下標  
  19.      * @param string $value 緩存變量的值  
  20.      * @return bool  
  21.      */   
  22.     abstract   public   function  store( $key $value );  
  23.       
  24.     /**  
  25.      * 刪除緩存變量  
  26.      *  
  27.      * @param string $key 緩存下標  
  28.      * @return Cache_Abstract  
  29.      */   
  30.     abstract   public   function   delete ( $key );  
  31.       
  32.     /**  
  33.      * 清(刪)除所有緩存  
  34.      *  
  35.      * @return Cache_Abstract  
  36.      */   
  37.     abstract   public   function  clear();  
  38.       
  39.     /**  
  40.      * 鎖定緩存變量  
  41.      *  
  42.      * @param string $key 緩存下標  
  43.      * @return Cache_Abstract  
  44.      */   
  45.     abstract   public   function  lock( $key );  
  46.   
  47.     /**  
  48.      * 緩存變量解鎖  
  49.      *  
  50.      * @param string $key 緩存下標  
  51.      * @return Cache_Abstract  
  52.      */   
  53.     abstract   public   function  unlock( $key );  
  54.   
  55.     /**  
  56.      * 取得緩存變量是否被鎖定  
  57.      *  
  58.      * @param string $key 緩存下標  
  59.      * @return bool  
  60.      */   
  61.     abstract   public   function  isLocked( $key );  
  62.   
  63.     /**  
  64.      * 確保不是鎖定狀態  
  65.      * 最多做$tries次睡眠等待解鎖,超時則跳過並解鎖  
  66.      *  
  67.      * @param string $key 緩存下標  
  68.      */   
  69.     public   function  checkLock( $key ) {  
  70.         if  (! $this ->isLocked( $key )) {  
  71.             return   $this ;  
  72.         }  
  73.           
  74.         $tries  = 10;  
  75.         $count  = 0;  
  76.         do  {  
  77.             usleep(200);  
  78.             $count  ++;  
  79.         } while  ( $count  <=  $tries  &&  $this ->isLocked( $key ));   // 最多做十次睡眠等待解鎖,超時則跳過並解鎖   
  80.   
  81.         $this ->isLocked( $key ) &&  $this ->unlock( $key );  
  82.           
  83.         return   $this ;  
  84.     }  
  85. }  
  86.   
  87.   
  88. /**  
  89.  * APC擴展緩存實現  
  90.  *   
  91.  *   
  92.  * @category   Mjie  
  93.  * @package    Cache  
  94.  * @author     流水孟春  
  95.  * @copyright  Copyright (c) 2008- <cmpan(at)qq.com>  
  96.  * @license    New BSD License  
  97.  * @version    $Id: Cache/Apc.php 版本號 2010-04-18 23:02 cmpan $  
  98.  */   
  99. class  Cache_Apc  extends  Cache_Abstract {  
  100.       
  101.     protected   $_prefix  =  'cache.mjie.net' ;  
  102.       
  103.     public   function  __construct() {  
  104.         if  (!function_exists( 'apc_cache_info' )) {  
  105.             throw   new  CacheException( 'apc extension didn/'t installed' );  
  106.         }  
  107.     }  
  108.       
  109.     /**  
  110.      * 保存緩存變量  
  111.      *  
  112.      * @param string $key  
  113.      * @param mixed $value  
  114.      * @return bool  
  115.      */   
  116.     public   function  store( $key $value ) {  
  117.         return  apc_store( $this ->_storageKey( $key ),  $value );  
  118.     }  
  119.       
  120.     /**  
  121.      * 讀取緩存  
  122.      *  
  123.      * @param string $key  
  124.      * @return mixed  
  125.      */   
  126.     public   function  fetch( $key ) {  
  127.         return  apc_fetch( $this ->_storageKey( $key ));  
  128.     }  
  129.       
  130.     /**  
  131.      * 清除緩存  
  132.      *  
  133.      * @return Cache_Apc  
  134.      */   
  135.     public   function  clear() {  
  136.         apc_clear_cache();  
  137.         return   $this ;  
  138.     }  
  139.       
  140.     /**  
  141.      * 刪除緩存單元  
  142.      *  
  143.      * @return Cache_Apc  
  144.      */   
  145.     public   function   delete ( $key ) {  
  146.         apc_delete($this ->_storageKey( $key ));  
  147.         return   $this ;  
  148.     }  
  149.       
  150.     /**  
  151.      * 緩存單元是否被鎖定  
  152.      *  
  153.      * @param string $key  
  154.      * @return bool  
  155.      */   
  156.     public   function  isLocked( $key ) {  
  157.         if  ((apc_fetch( $this ->_storageKey( $key ) .  '.lock' )) === false) {  
  158.             return  false;  
  159.         }  
  160.           
  161.         return  true;  
  162.     }  
  163.       
  164.     /**  
  165.      * 鎖定緩存單元  
  166.      *  
  167.      * @param string $key  
  168.      * @return Cache_Apc  
  169.      */   
  170.     public   function  lock( $key ) {  
  171.         apc_store($this ->_storageKey( $key ) .  '.lock' '' , 5);  
  172.         return   $this ;  
  173.     }  
  174.       
  175.     /**  
  176.      * 緩存單元解鎖  
  177.      *  
  178.      * @param string $key  
  179.      * @return Cache_Apc  
  180.      */   
  181.     public   function  unlock( $key ) {  
  182.         apc_delete($this ->_storageKey( $key ) .  '.lock' );  
  183.         return   $this ;  
  184.     }  
  185.       
  186.     /**  
  187.      * 完整緩存名  
  188.      *  
  189.      * @param string $key  
  190.      * @return string  
  191.      */   
  192.     private   function  _storageKey( $key ) {  
  193.         return   $this ->_prefix .  '_'  .  $key ;  
  194.     }  
  195. }  
  196.   
  197. /**  
  198.  * 文件緩存實現  
  199.  *   
  200.  *   
  201.  * @category   Mjie  
  202.  * @package    Cache  
  203.  * @author     流水孟春  
  204.  * @copyright  Copyright (c) 2008- <cmpan(at)qq.com>  
  205.  * @license    New BSD License  
  206.  * @version    $Id: Cache/File.php 版本號 2010-04-18 16:46 cmpan $  
  207.  */   
  208. class  Cache_File  extends  Cache_Abstract {  
  209.       
  210.     protected   $_cachesDir  =  'cache' ;  
  211.       
  212.     public   function  __construct() {  
  213.         if  (defined( 'DATA_DIR' )) {  
  214.             $this ->_setCacheDir(DATA_DIR .  '/cache' );  
  215.         }  
  216.     }  
  217.       
  218.     /**  
  219.      * 獲取緩存文件  
  220.      *  
  221.      * @param string $key  
  222.      * @return string  
  223.      */   
  224.     protected   function  _getCacheFile( $key ) {  
  225.         return   $this ->_cachesDir .  '/'  .  substr ( $key , 0, 2) .  '/'  .  $key  .  '.php' ;  
  226.     }  
  227.   
  228.     /**  
  229.      * 讀取緩存變量  
  230.      * 爲防止信息泄露,緩存文件格式爲php文件,並以"<?php exit;?>"開頭  
  231.      *   
  232.      * @param string $key 緩存下標  
  233.      * @return mixed  
  234.      */   
  235.     public   function  fetch( $key ) {  
  236.         $cacheFile  = self::_getCacheFile( $key );  
  237.         if  ( file_exists ( $cacheFile ) &&  is_readable ( $cacheFile )) {  
  238.             return  unserialize(@ file_get_contents ( $cacheFile , false, NULL, 13));  
  239.         }  
  240.   
  241.         return  false;  
  242.     }  
  243.   
  244.     /**  
  245.      * 緩存變量  
  246.      * 爲防止信息泄露,緩存文件格式爲php文件,並以"<?php exit;?>"開頭  
  247.      *  
  248.      * @param string $key 緩存變量下標  
  249.      * @param string $value 緩存變量的值  
  250.      * @return bool  
  251.      */   
  252.     public   function  store( $key $value ) {  
  253.         $cacheFile  = self::_getCacheFile( $key );  
  254.         $cacheDir   = dirname( $cacheFile );  
  255.   
  256.         if (! is_dir ( $cacheDir )) {  
  257.             if (!@ mkdir ( $cacheDir , 0755, true)) {  
  258.                 throw   new  CacheException( "Could not make cache directory" );  
  259.             }  
  260.         }  
  261.   
  262.         return  @ file_put_contents ( $cacheFile '<?php exit;?>'  . serialize( $value ));  
  263.     }  
  264.   
  265.     /**  
  266.      * 刪除緩存變量  
  267.      *  
  268.      * @param string $key 緩存下標  
  269.      * @return Cache_File  
  270.      */   
  271.     public   function   delete ( $key ) {  
  272.         if ( empty empty ( $key )) {  
  273.             throw   new  CacheException( "Missing argument 1 for Cache_File::delete()" );  
  274.         }  
  275.           
  276.         $cacheFile  = self::_getCacheFile( $key );  
  277.         if (!@unlink( $cacheFile )) {  
  278.             throw   new  CacheException( "Cache file could not be deleted" );  
  279.         }  
  280.   
  281.         return   $this ;  
  282.     }  
  283.   
  284.     /**  
  285.      * 緩存單元是否已經鎖定  
  286.      *  
  287.      * @param string $key  
  288.      * @return bool  
  289.      */   
  290.     public   function  isLocked( $key ) {  
  291.         $cacheFile  = self::_getCacheFile( $key );  
  292.         clearstatcache();  
  293.         return   file_exists ( $cacheFile  .  '.lock' );  
  294.     }  
  295.   
  296.     /**  
  297.      * 鎖定  
  298.      *  
  299.      * @param string $key  
  300.      * @return Cache_File  
  301.      */   
  302.     public   function  lock( $key ) {  
  303.         $cacheFile  = self::_getCacheFile( $key );  
  304.         $cacheDir   = dirname( $cacheFile );  
  305.         if (! is_dir ( $cacheDir )) {  
  306.             if (!@ mkdir ( $cacheDir , 0755, true)) {  
  307.                 if (! is_dir ( $cacheDir )) {  
  308.                     throw   new  CacheException( "Could not make cache directory" );  
  309.                 }  
  310.             }  
  311.         }  
  312.   
  313.         // 設定緩存鎖文件的訪問和修改時間   
  314.         @touch($cacheFile  .  '.lock' );  
  315.         return   $this ;  
  316.     }  
  317.     
  318.     /**  
  319.      * 解鎖  
  320.      *  
  321.      * @param string $key  
  322.      * @return Cache_File  
  323.      */   
  324.     public   function  unlock( $key ) {  
  325.         $cacheFile  = self::_getCacheFile( $key );  
  326.         @unlink($cacheFile  .  '.lock' );  
  327.         return   $this ;  
  328.     }  
  329.   
  330.     /**  
  331.      * 設置文件緩存目錄  
  332.      * @param string $dir  
  333.      * @return Cache_File  
  334.      */   
  335.     protected   function  _setCacheDir( $dir ) {  
  336.         $this ->_cachesDir = rtrim( str_replace ( '//', ' / ', trim($dir)), ' /');  
  337.         clearstatcache();  
  338.         if (! is_dir ( $this ->_cachesDir)) {  
  339.             mkdir ( $this ->_cachesDir, 0755, true);  
  340.         }  
  341.         //   
  342.         return   $this ;  
  343.     }  
  344.               
  345.     /**  
  346.      * 清空所有緩存  
  347.      *  
  348.      * @return Cache_File  
  349.      */   
  350.     public   function  clear() {  
  351.         // 遍歷目錄清除緩存   
  352.         $cacheDir  =  $this ->_cachesDir;  
  353.         $d  = dir( $cacheDir );  
  354.         while (false !== ( $entry  =  $d ->read())) {  
  355.             if ( '.'  ==  $entry [0]) {  
  356.                 continue ;  
  357.             }  
  358.               
  359.             $cacheEntry  =  $cacheDir  .  '/'  .  $entry ;  
  360.             if ( is_file ( $cacheEntry )) {  
  361.                 @unlink($cacheEntry );  
  362.             } elseif ( is_dir ( $cacheEntry )) {  
  363.                 // 緩存文件夾有兩級   
  364.                 $d2  = dir( $cacheEntry );  
  365.                 while (false !== ( $entry  =  $d2 ->read())) {  
  366.                     if ( '.'  ==  $entry [0]) {  
  367.                         continue ;  
  368.                     }  
  369.                       
  370.                     $cacheEntry  .=  '/'  .  $entry ;  
  371.                     if ( is_file ( $cacheEntry )) {  
  372.                         @unlink($cacheEntry );  
  373.                     }  
  374.                 }  
  375.                 $d2 ->close();  
  376.             }         
  377.         }  
  378.         $d ->close();  
  379.           
  380.         return   $this ;  
  381.     }     
  382. }  
  383.   
  384. /**  
  385.  * 緩存單元的數據結構  
  386.  * array(  
  387.  *     'time' => time(),    // 緩存寫入時的時間戳  
  388.  *     'expire' => $expire, // 緩存過期時間  
  389.  *     'valid' => true,     // 緩存是否有效  
  390.  *     'data' => $value     // 緩存的值  
  391.  * );  
  392.  */   
  393. final class  Cache {  
  394.     /**  
  395.      * 緩存過期時間長度(s)  
  396.      *  
  397.      * @var int  
  398.      */   
  399.     private   $_expire  = 3600;  
  400.   
  401.     /**  
  402.      * 緩存處理類  
  403.      *  
  404.      * @var Cache_Abstract  
  405.      */   
  406.     private   $_storage  = null;  
  407.   
  408.     /**  
  409.      * @return Cache  
  410.      */   
  411.     static   public   function  createCache( $cacheClass  =  'Cache_File' ) {  
  412.         return   new  self( $cacheClass );  
  413.     }  
  414.   
  415.     private   function  __construct( $cacheClass ) {  
  416.         $this ->_storage =  new   $cacheClass ();  
  417.     }  
  418.   
  419.     /**  
  420.      * 設置緩存  
  421.      *  
  422.      * @param string $key  
  423.      * @param mixed $value  
  424.      * @param int $expire  
  425.      */   
  426.     public   function  set( $key $value $expire  = false) {  
  427.         if  (! $expire ) {  
  428.             $expire  =  $this ->_expire;  
  429.         }  
  430.           
  431.         $this ->_storage->checkLock( $key );  
  432.           
  433.         $data  =  array ( 'time'  => time(),  'expire'  =>  $expire 'valid'  => true,  'data'  =>  $value );  
  434.         $this ->_storage->lock( $key );  
  435.           
  436.         try {  
  437.             $this ->_storage->store( $key $data );  
  438.             $this ->_storage->unlock( $key );  
  439.         } catch (CacheException $e ) {  
  440.             $this ->_storage->unlock( $key );  
  441.             throw   $e ;  
  442.         }  
  443.     }  
  444.   
  445.     /**  
  446.      * 讀取緩存  
  447.      *  
  448.      * @param string $key  
  449.      * @return mixed  
  450.      */   
  451.     public   function  get( $key ) {  
  452.         $data  =  $this ->fetch( $key );  
  453.         if  ( $data  &&  $data [ 'valid' ] && ! $data [ 'isExpired' ]) {  
  454.             return   $data [ 'data' ];  
  455.         }  
  456.           
  457.         return  false;  
  458.     }  
  459.   
  460.     /**  
  461.      * 讀緩存,包括過期的和無效的,取得完整的存貯結構  
  462.      *  
  463.      * @param string $key  
  464.      */   
  465.     public   function  fetch( $key ) {  
  466.         $this ->_storage->checkLock( $key );  
  467.         $data  =  $this ->_storage->fetch( $key );  
  468.         if  ( $data ) {  
  469.             $data [ 'isExpired' ] = (time() -  $data [ 'time' ]) >  $data [ 'expire' ] ? true : false;  
  470.             return   $data ;  
  471.         }  
  472.           
  473.         return  false;  
  474.     }  
  475.   
  476.     /**  
  477.      * 刪除緩存  
  478.      *  
  479.      * @param string $key  
  480.      */   
  481.     public   function   delete ( $key ) {  
  482.         $this ->_storage->checkLock( $key )  
  483.                        ->lock($key )  
  484.                        ->delete ( $key )  
  485.                        ->unlock($key );  
  486.     }  
  487.       
  488.     public   function  clear() {  
  489.         $this ->_storage->clear();  
  490.     }  
  491.   
  492.     /**  
  493.      * 把緩存設爲無效  
  494.      *  
  495.      * @param string $key  
  496.      */   
  497.     public   function  setInvalidate( $key ) {  
  498.         $this ->_storage->checkLock( $key )  
  499.                        ->lock($key );  
  500.         try {  
  501.             $data  =  $this ->_storage->fetch( $key );  
  502.             if  ( $data ) {  
  503.                 $data [ 'valid' ] = false;  
  504.                 $this ->_storage->store( $key $data );  
  505.             }  
  506.             $this ->_storage->unlock( $key );  
  507.         } catch (CacheException $e ) {  
  508.             $this ->_storage->unlock( $key );  
  509.             throw   $e ;  
  510.         }  
  511.     }  
  512.       
  513.     /**  
  514.      * 設置緩存過期時間(s)  
  515.      *  
  516.      * @param int $expire  
  517.      */   
  518.     public   function  setExpire( $expire ) {  
  519.         $this ->_expire = (int)  $expire ;  
  520.         return   $this ;  
  521.     }  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章