2014-12-04 106 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 
    } 
}