Класс Cacher (специально для Тормоза)

22.11.2010

В очередной раз Тормоз устроил дичайший холивар в своем блоге.

Я туда боюсь заходить – зашибут ещё ненароком. Между тем, задача как мне кажется легко решается. Вот накидал за 10 минут:

  1. <?php
  2.  
  3. class Cacher {
  4.     // Время жизни кэша в секундах
  5.     public $timeout = 10;
  6.  
  7.     // Массив с кэшем (хранится в памяти т. к. это всего лишь пример)
  8.     private $cache = array();
  9.  
  10.     public function __call($name, $args) {
  11.         return $this->realCall($name, $args);
  12.     }
  13.  
  14.     public function call($callback) {
  15.         $args = array();
  16.         if (func_num_args() > 1) {
  17.             $args = array_slice(func_get_args(), 1);
  18.         }
  19.         return $this->realCall($callback, $args);
  20.     }
  21.  
  22.     private function realCall($callback, $args = array()) {
  23.         $cacheKey = $this->getKey($callback, $args);
  24.  
  25.         // Выводим из памяти если существует кэш и он не просрочен
  26.         if ($this->hasCache($cacheKey)) {
  27.             echo "From cache with love.<br/>\r\n";
  28.             return $this->getCache($cacheKey);
  29.         }
  30.  
  31.         $data = call_user_func_array($callback, $args);
  32.         $this->setCache($cacheKey, $data);
  33.  
  34.         return $data;
  35.     }
  36.  
  37.     // Генерирует хэш ключ для кэша :)
  38.     private function getKey() {
  39.         $serialized = serialize(func_get_args());
  40.         $key = md5($serialized);
  41.         return $key;
  42.     }
  43.  
  44.     private function hasCache($key) {
  45.         if (isset($this->cache[$key])) {
  46.             if ($this->cache[$key]->expire > time()) {
  47.                 return true;
  48.             } else {
  49.                 // Удаляем просроченный кэш
  50.                 unset($this->cache[$key]);
  51.             }
  52.         }
  53.         return false;
  54.     }
  55.  
  56.     private function getCache($key) {
  57.         return $this->cache[$key]->data;
  58.     }
  59.  
  60.     private function setCache($key, $data) {
  61.         $this->cache[$key] = (object) array(
  62.             'expire' => time() + $this->timeout,
  63.             'data' => $data,
  64.         );
  65.     }
  66. }
  67.  
  68.  
  69. ?>

И пример использования:

  1. <?php
  2.  
  3. require './Cacher.php';
  4.  
  5. $cacher = new Cacher;
  6.  
  7. // Через __call
  8. $cacher->file_get_contents('http://jeck.ru');
  9. $cacher->file_get_contents('http://jeck.ru');
  10.  
  11. class TestClass {
  12.     private $param = 'paramValue';
  13.  
  14.     public function testMethod($url) {
  15.         return file_get_contents($url);
  16.     }
  17. }
  18.  
  19. $testClass = new TestClass;
  20. // Через call что бы передать имя и метод класса
  21. $cacher->call(array($testClass, 'testMethod'), 'http://jeck.ru');
  22.  
  23. ?>

  1. # Тормоз:

    Эх, Джек, не то это. С функциями и я сделал ($cacher->file_get_contents(URL)), а вот если вместо file_get_contents() будет вызов метода объекта, облом.

    Твой вариант, и предлагаемые у меня в комментах все грешат изменением синтаксиса уже рабочего кода – то в скобки оборачивается всё, то ещё что-то.

    А в идеале, просто подставляешь кэшер перед вызовом и всё. Это было бы круто. Но, похоже, просто невозможно.