Это паттерн для моделей использующих Zend_Cache и магический метод __call.
Простая идея
Изначальный смысл в том, что модель должна иметь возможность возвращать не кэшированные или кэшированные вызовы, без постоянной инициализации определенного объекта. Должно происходить легкое переключение между двумя вызовами, и кэш должен приходить уже с моделью объекта.
Старый способ
Перед представлением паттерна кэширования, я создавал бы объект, который потом бы использовал Zend_Cache_Frontend_Class, потом инициализировал новую сущность моей модели и там переопределил метод, который действует как прокси, но использует кэш. И если этого не достаточно, я инициализирую их оба, как в этом примере:
<?php
$model = MyModel();
$model_cached = MyModelCached();
$values_direct = $model->doStuff();
$values_cached = $model_cached->doStuff();
Новый способ
Итак, Матиас спросил меня: Будет ли это лучше, если бы кэш уже был доступен в модели, и вы могли бы делать так:
<?php
$model = MyModel();
$values_direct = $model->doStuff();
$values_cached = $model->cache->doStuff();
Отличная идея. Как вы можете видеть, предложенный способ, содержит немного кода, он интуитивно понятен и легко меняется, если вы захотите переключаться между кэшируемыми и некэшируемыми вызовами.
Код
Первое что нужно сделать, это создать объект, инициализирующий кэш. Мы инициализируем кэш с помощью Zend_Cache и затем используем функцию __call для проверки или вызов существует в кэшируемом объекте. Это позволит нам делать только достоверные вызовы.
<?php
class BaseModelCache {
private $object;
private $cache;
public function __construct($object) {
$backendName = 'File';
$frontendName = 'Class';
$frontendOptions = array(
'lifetime' => 1800,
);
$backendOptions = array(
'cache_dir' => '/my/cache/dir/',
);
$this->object = $object;
$frontendOptions['cached_entity'] = $object;
try {
Zend_Loader::loadClass('Zend_Cache');
$this->cache = Zend_Cache::factory($frontendName, $backendName, $frontendOptions, $backendOptions);
} catch(Exception $e) {
throw($e);
}
}
public function __call($method, $args) {
$class = get_class($this->object);
$class_methods = get_class_methods($class);
if(in_array($method , $class_methods)) {
$caller = Array($this->cache, $method);
return call_user_func_array($caller, $args);
}
throw new Exception( " Метод " . $method . " не существует в классе " . get_class($class ) . "." );
}
}
Вторым шагом будет создать базовый класс модели, который будет использоваться для всех остальных моделей. Он будет инициализировать объект кэша, используя BaseModelCache и делать его доступным как public-свойство:
<?php
abstract class BaseModel {
public $cache;
public function __construct() {
$this->cache = new BaseModelCache($this);
}
}
Вуаля! Сейчас мы можем создавать модели, расширяя BaseModel. Кэш будет доступен как описано выше