2014-12-04 45 views
0

我試圖用Memcache中的函數擴展我的PDO類。特別是,我創建了一個函數cache_execute,它允許我首先檢查結果是否存在於緩存中,然後返回緩存中的信息,或者如果信息尚不存在,則返回數據庫中的信息在緩存中(以及將信息中的緩存,如果不存在的話)模擬PDOStatement ::執行

這裏是我當前的代碼示例:

namespace trf; 
class StatementWithCaching extends \PDOStatement { 
    public $db; 
    public $cache; 
    protected function __construct(&$db) { 
     $this->db =& $db; 
    } 

    function cache_execute($array = NULL , $cache = FALSE , $cacheTime = 1800) { 
     if(is_a($cache , 'Memcache')) { 
      $query = $this->queryString; 
      foreach ($array as $key => $value) { 
       $query = str_replace(':' . $key , "'" . addslashes($value) . "'", $query); 
      } 
      try { 
       $memResults = $this->mconn->get(md5($this->queryString)); 
      } 
      catch (\Exception $e) { 
       $memResults = FALSE; 
      } 

     } else { 

     } 
    } 
} 

我的問題是 - 我怎麼把信息從緩存中檢索並存儲在可由PDOStatement::fetch()PDOStatement::fetchAll()等檢索的地方

我的目標是能夠運行StatementWithCaching::execute()StatementWithCaching::cache_execute()並仍以相同方式檢索結果(使用StatementWithCaching::fetch()StatementWithCaching::fetchAll())。

+0

你不能,而不是與pdostatement對象。他們不會知道任何有關您的緩存的信息。你的主要的pdo包裝應該包裝「準備」/「執行」並返回你自己的緩存感知對象。 – 2014-12-04 14:53:33

+0

問題不在於緩存,它知道如何將信息存儲在可由PDOStatement :: fetch()或PDOStatement :: fetchAll()檢索的位置,除非我誤解了你。 – 2014-12-04 14:55:39

+0

,就像我說過的,不可能使用pdostatement對象。它不知道你的緩存。所以你的pdo包裝必須擴展「準備」來返回一個「MyCacheAwarePDOStatement」對象,而該對象擴展了pdostatement。 – 2014-12-04 14:56:43

回答

0

我能夠通過延伸PDOStatement::fetch()PDOStatement::fetchAll()函數來解決該問題。

namespace trf; 
class StatementWithCaching extends \PDOStatement { 
    protected $db; 
    protected $cache; 
    protected $cacheReturn; 
    protected $cacheQuery; 
    protected $queryCacheTime; 
    protected function __construct(&$db) { 
     $this->db =& $db; 
    } 

    function cache_execute($array = NULL , $cache = FALSE , $cacheTime = 1800) { 
     if(is_a($cache , 'Memcache')) { 
      $this->cache = $cache; 
      $this->queryCacheTime = $cacheTime; 
      $this->cacheQuery = $this->queryString; 
      if($array !== NULL) { 
       foreach ($array as $key => $value) { 
        $this->cacheQuery = str_replace(':' . $key , "'" . addslashes($value) . "'", $this->cacheQuery); 
       } 
      } 
      $this->debugData('Trying to get data from cache for query: ' . $this->cacheQuery . ' (' . md5($this->cacheQuery) . ')'); 
      $this->cacheQuery = md5($this->cacheQuery); 
      try { 
       $this->cacheReturn = $this->cache->get($this->cacheQuery); 
       $this->debugData('Reporting return: ' . var_export($this->cacheReturn , TRUE)); 
      } 
      catch (\Exception $e) { 
       $this->cacheReturn = FALSE; 
       $this->debugData($e->getMessage()); 
      } 
      if(is_null($this->cacheReturn) || $this->cacheReturn == FALSE || is_null($this->cacheQuery) || !is_a($this->cache , 'Memcache')) { 
       if ($array === null) { 
        parent::execute(); 
       } else { 
        parent::execute($array); 
       } 
      } 
     } else { 
      if ($array === null) { 
       parent::execute(); 
      } else { 
       parent::execute($array); 
      } 
     } 
    } 

    function fetch($fetchStyle = \PDO::FETCH_BOTH, $cursor_orientation = \PDO::FETCH_ORI_NEXT , $cursor_offset = 0) { 
     if(is_null($this->cacheReturn) || $this->cacheReturn == FALSE || is_null($this->cacheQuery) || !is_a($this->cache , 'Memcache')) { 
      $fullResults = parent::fetchAll(); 
      if(is_a($this->cache , 'Memcache')) { 
       $this->debugData('Inserting data into cache:' . print_r($fullResults , TRUE)); 
       $this->cache->set($this->cacheQuery , $fullResults , MEMCACHE_COMPRESSED , $cacheTime); 
      } 
      return parent::fetch($fetchStyle , $cursor_orientation = \PDO::FETCH_ORI_NEXT , $cursor_offset = 0); 
     } 
     else { 
      $this->debugData('Returning Cached Results'); 
      switch ($fetchStyle) { 
       case \PDO::FETCH_BOTH: 
        return $this->cacheReturn[$cursor_offset]; 
        break; 

       case \PDO::FETCH_ASSOC: 
        $data = $this->cacheReturn[$cursor_offset]; 
        foreach ($data as $key => $value) { 
         if(is_numeric($key)) { 
          unset($data[$key]); 
         } 
        } 
        return $data; 
        break; 

       case \PDO::FETCH_LAZY: 
        $data = $this->cacheReturn[$cursor_offset]; 
        $return = new \stdClass(); 
        foreach ($data as $key => $value) { 
         if(!is_numeric($key)) { 
          $return->$key = $value; 
         } 
        } 
        return $return; 
        break; 

       case \PDO::FETCH_OBJ: 
        $data = $this->cacheReturn[$cursor_offset]; 
        $return = new \stdClass(); 
        foreach ($data as $key => $value) { 
         if(!is_numeric($key)) { 
          $return->$key = $value; 
         } 
        } 
        return $return; 
        break; 

       default: 
        return $this->cacheReturn[$cursor_offset]; 
        break; 
      } 
     } 
    } 

    function fetchAll() { 
     if(is_null($this->cacheReturn) || $this->cacheReturn == FALSE || is_null($this->cacheQuery) || !is_a($this->cache , 'Memcache')) { 
      $fullResults = parent::fetchAll(); 
      if(is_a($this->cache , 'Memcache')) { 
       $this->debugData('Inserting data into cache: ' . print_r($fullResults , TRUE)); 
       $this->cache->set($this->cacheQuery , $fullResults , MEMCACHE_COMPRESSED , $this->queryCacheTime); 
      } 
      return $fullResults; 
     } else { 
      $this->debugData('Returning Cached Results'); 
      return $this->cacheReturn; 
     } 
    } 

    private function debugData($data) { 
     if(isset($_GET['debug']) && $_GET['debug'] = DEBUGVAL) { 
      print('<pre>'); 
      print_r($data); 
      print('</pre>'); 
     } 
    } 
} 

雖然解決方案仍然不能處理所有可以用於任何PDOStatement::fetch()PDOStatement::fetchAll()設置的標誌,它可以進一步擴展這樣做。

我已經運行了一些測試,迄今爲止效果很好。

1

我強烈建議您不要將緩存訪問邏輯與您的數據庫訪問邏輯混合在一起。換句話說,我不會嘗試擴展DB特定的類來寫入緩存。畢竟,當你不需要的時候,爲什麼要將諸如語句,結果集等概念引入簡單的緩存層。

我會改爲更高層次的抽象,也許是一個類,你可以通過一個有效的數據庫連接和一個有效的連接到你的緩存層(在你的情況下是Memcache),並讓這個類編排閱讀邏輯/寫入緩存和數據庫。

作爲高電平例子(顯然這省略了錯誤/異常處理和例如):

class WriteTroughCache { 
    protected $pdo; 
    protected $cache; 
    protected $cache_ttl = 1000; 
    // not shown variouos other options that might be needed for cache or DB 

    public function __construct(PDO $pdo, Memcache $cache, $options = array()) { 
     $this->pdo = $pdo; 
     $this->cache = $cache; 
     if (!empty($options)) { 
      // not shown load options from array into option properties including cache_ttl 
     }  
    } 

    public get($key) { 
     $result = $this-cache->get($key); 
     if ($result) { 
      return $result; 
     } 
     // not in cache, get from DB 
     $value = $this->db_get($key); 
     if (false === $value) { 
      // key did not exist in DB 
      return false; 
     } else { 
      // key found in DB 
      $this->cache->set($key, $value, 0, $this->cache_ttl); 
      return $value; 
     } 
    } 

    public function set($key, $value) { 
     // see if key exists 
     // if so, update cache first 
     $value = $this->get($key); 
     if($value) { 
      $this->cache->set($key, $value, 0 , $this->cache_ttl); 
     }   
     return $this->db_set($key, $value); 
    } 

    public function db_get($key) { 
     // not shown perform DB query using PDO object 
     // return value at key if found or false if not found 
    } 

    public function db_set($key, $value) { 
     // not shown perform DB query using PDO object 
     // return true or false based on success of insert 
    } 
}