# Фронтэнды Zend_Cache

## Zend_Cache_Core

### Введение

Фронтэнд `Zend_Cache_Core` является особым, так как это ядро всего модуля. Это фронтэнд общего назначения и он расширяется другими классами.

Все фронтэнды наследуют от класса `Zend_Cache_Core`, поэтому его методы и опции, описанные ниже, должны быть доступны в других фронтэндах и не будут описываться далее.

### Доступные опции

Эти опции передаются фабричному методу, как было показано в предыдущих примерах.

#### Опции Zend_Cache_Core

Опция | Тип данных | Значение по умолчанию | Описание
--- | --- | --- | ---
caching | Boolean | `TRUE` | Включает/отключает кэширование (может быть очень полезным при отладке кэшируемых скриптов).

cache_id_prefix

String

`NULL`

Префикс для всех идентификаторов кэша. Если установлен в `NULL`, то префикс не будет использоваться. Префикс идентификатора кэша в первую очередь создает пространство имен в кэше, что позволяет нескольким приложениям или веб-сайтам использовать общий кэш. Любое приложение или веб-сайт может использовать свой префикс идентификаторов кэша, благодаря чему отдельные идентификаторы кеша могут использоваться многократно.

lifetime | Integer | 3600 | Время жизни кэша (в секундах), если установлен в `NULL`, то кэш имеет бесконечное время жизни.
logging | Boolean | `FALSE` | Если установлен в `TRUE`, то включается логирование через `Zend_Log` (но система будет работать медленнее).
write_сontrol | Boolean | `TRUE` | Включает/отключает контроль записи (кэш читается сразу после записи для выявления поврежденных записей), включение write_control немного замедлит запись кэша, но не чтение. Этот контроль поможет выявить некоторые поврежденные файлы кэша, но не является совершенным.
automatic_serialization | Boolean | `FALSE` | Включает/отключает автоматическую сериализацию, она может использоваться для сохранения напрямую данных, которые не являются строками (но это будет медленнее).
automatic_cleaning_factor | Integer | 10 | Отключает/настраивает процесс автоматической очистки (сборки мусора): 0 означает, что автоматическая чистка кэша не производится, 1 означает систематическую очистку кэша, x (integer) > 1 означает, что автоматическая чистка производится случайным образом 1 раз на x записей кэша.
ignore_user_abort | Boolean | `FALSE` | Если установлен в true, то ядро будет устанавливать PHP-флаг ignore_user_abort в методе save() во избежание порчи кэша в некоторых случаях.

### Примеры

Пример был дан в самом начале данного раздела руководства.

Если вы храните в кэше только строки (с опцией automatic_serialization возможно хранить некоторые булевы значения), вы можете использовать более компактную конструкцию, как показано ниже:

    // предполагается, что переменная $cache уже установлена

    $id = 'myBigLoop'; // идентификатор того, что мы хотим закэшировать

    if (!($data = $cache->load($id))) {
        // промах кэша

        $data = '';
        for ($i = 0; $i < 10000; $i++) {
            $data = $data . $i;
        }

        $cache->save($data);

    }

    // [...] делаем что-либо с данными (отображение, передача и т.д.)

Если вы хотите закэшировать несколько блоков или экземпляров данных, то принцип будет тот же:

    // убедитесь, что используете уникальные идентификаторы:
    $id1 = 'foo';
    $id2 = 'bar';

    // блок 1
    if (!($data = $cache->load($id1))) {
        // промах кэша

        $data = '';
        for ($i=0;$i<10000;$i++) {
            $data = $data . $i;
        }

        $cache->save($data);

    }
    echo($data);

    // эта часть не кэшируется
    echo('НЕ КЭШИРУЕТСЯ! ');

    // блок 2
    if (!($data = $cache->load($id2))) {
        // промах кэша

        $data = '';
        for ($i=0;$i<10000;$i++) {
            $data = $data . '!';
        }

        $cache->save($data);

    }
    echo($data);

Если вы хотите кэшировать специальные значения (булево значение через опцию "automatic_serialization") или пустую строку, то компактная форма, приведенная выше, уже не подходит. Проверка на наличие записи кэша должна производиться созданным для этого методом.

    // Копмпактная форма. Не подходит, если могут кэшироваться
    // пустые строки и значения булевого типа
    if (!($data = $cache->load($id))) {

        // промах кэша

        // [...] получаем данные и присваиваем их переменной $data

        $cache->save($data);

    }

    // делаем что-либо с данными

    // [...]

    // Полная форма, будет работать в любом случае
    if (!($cache->test($id))) {

        // промах кэша

        // [...] получаем данные и присваиваем их переменной $data

        $cache->save($data);

    } else {

        // попадание в кэш

        $data = $cache->load($id);

    }

    // делаем что-либо с данными

## Zend_Cache_Frontend_Output

### Введение

`Zend_Cache_Frontend_Output` является фронтэндом, собирающим выходные данные. Он использует буферизацию вывода (output buffering) в PHP для сохранения всего, что выводится между его методами `start()` и `end()`.

### Доступные опции

Этот фронтэнд не имеет каких-либо специальных опций, отличных от опций `Zend_Cache_Core`.

### Примеры

Пример был дан в самом начале данного руководства. Здесь он с небольшими изменениями:

    // если имеет место промах кэша,
    // то начинается буферизация вывода
    if (!($cache->start('mypage'))) {

        // все выводится, как обычно
        echo 'Hello world! ';
        echo 'This is cached ('.time().') ';

        $cache->end(); // завершение буферизации вывода

    }

    echo 'This is never cached ('.time().').';

Используя эту форму, довольно легко установить кэширование вывода в уже работающем проекте с незначительным рефакторингом кода или совсем без него.

## Zend_Cache_Frontend_Function

### Введение

`Zend_Cache_Frontend_Function` сохраняет в кэш результаты вызова функции. Он имеет единственный основной метод `call()`, который принимает имя функции и параметры вызова в виде массива.

### Доступные опции

#### Опции Zend_Cache_Frontend_Function

Опция | Тип данных | Значение по умолчанию | Описание
--- | --- | --- | ---
cache_by_default | Boolean | `TRUE` | Если равен true, то вызовы функции по умолчанию кэшируются.
cached_functions | Array |  | Имена функций, которые всегда кэшируются.
non_cached_functions | Array |  | Имена функций, которые никогда не должны кэшироваться.

### Примеры

Функция `call()` используется так же, как и `call_user_func_array()` в PHP:

    $cache->call('veryExpensiveFunc', $params);

    // $params является массивом
    // Например, если нужно вызвать с кэшированием
    // veryExpensiveFunc(1, 'foo', 'bar'),
    // то вы должны использовать
    // $cache->call('veryExpensiveFunc', array(1, 'foo', 'bar'))

`Zend_Cache_Frontend_Function` достаточно интеллектуален, чтобы кэшировать как возвращаемое функцией значение, так и данные, выводимые внутри нее.

Вы можете передавать любые как встроенные, так и определенные пользователем функции, за исключением `array()`, `echo()`, `empty()`, `eval()`, `exit()`, `isset()`, `list()`, `print()` и `unset()`.

## Zend_Cache_Frontend_Class

### Введение

`Zend_Cache_Frontend_Class` отличается от `Zend_Cache_Frontend_Function` тем, что позволяет кэшировать объекты и статические вызовы методов.

### Доступные опции

#### Опции Zend_Cache_Frontend_Class

Опция | Тип данных | Значение по умолчанию | Описание
--- | --- | --- | ---
cached_entity (required) | Mixed |  | Если установлен как имя класса, то будет кэшироваться абстрактный класс и будут использоваться только статические вызовы; если установлен как объект, то будут кэшироваться методы объекта.
cache_by_default | Boolean | `TRUE` | Если установлен в `TRUE`, то вызовы будут кэшироваться по умолчанию.
cached_methods | Array |  | Имена методов, которые должны всегда кэшироваться.
non_cached_methods | Array |  | Имена методов, которые никогда не должны кэшироваться.

### Примеры

Кэширование статических вызовов:

    <?php
    class Test {

        // Статический метод
        public static function foobar($param1, $param2) {
            echo "foobar_output($param1, $param2)";
            return "foobar_return($param1, $param2)";
        }

    }

    // [...]
    $frontendOptions = array(
        'cached_entity' => 'Test' // имя класса
    );
    // [...]

    // Кэшируемый вызов
    $result = $cache->foobar('1', '2');

Кэширование обычных вызовов методов:

    class Test {

        private $_string = 'hello !';

        public function foobar2($param1, $param2) {
            echo($this->_string);
            echo "foobar2_output($param1, $param2)";
            return "foobar2_return($param1, $param2)";
        }

    }

    // [...]
    $frontendOptions = array(
        'cached_entity' => new Test() // экземпляр класса
    );
    // [...]

    // Кэшируемый вызов
    $result = $cache->foobar2('1', '2');

## Zend_Cache_Frontend_File

### Введение

`Zend_Cache_Frontend_File` является фронтэндом, который управляется временем изменения "ведущего файла". Он очень полезен для кэширования конфигураций или шаблонов. Можно использовать несколько ведущих файлов.

Например, у вас есть конфигурационный файл XML. Он парсится функцией, которая возвращает объект конфигурации (наподобие `Zend_Config`). С помощью `Zend_Cache_Frontend_File` вы можете сохранять объект конфигурации в кэш, чтобы избежать повторного парсинга конфигурационного файла XML. Время жизни кэша будет зависеть от ведущего файла - если конфигурационный файл XML изменится, то кэш сразу становится недействительным.

### Доступные опции

#### Опции Zend_Cache_Frontend_File

Опция | Тип данных | Значение по умолчанию | Описание
--- | --- | --- | ---
master_file (не рекомендуется к использованию) | String | '' | Полные путь и имя ведущего файла
master_files | Array | `array()` | Массив полных путей к ведущим файлам
master_files_mode | String | `Zend_Cache_Frontend_File::MODE_OR` | `Zend_Cache_Frontend_File::MODE_AND` или `Zend_Cache_Frontend_File::MODE_OR`; если `MODE_AND`, то все ведущие файлы должны быть изменены для того, чтобы кэш стал недействительным если `MODE_OR`, то достаточно изменения одного ведущего файла, чтобы кэш стал недействительным
ignore_missing_master_files | Boolean | `FALSE` | если равен `TRUE`, то отсутствующие ведущие файлы игнорируются, иначе бросается исключение

### Примеры

Этот фронтэнд используется так же, как и `Zend_Cache_Core`. Специальные примеры не нужны, единственное, что надо сделать — это указать masterFile при использовании фабрики.

## Zend_Cache_Frontend_Page

### Введение

`Zend_Cache_Frontend_Page` похож на `Zend_Cache_Frontend_Output`, но предназначена для кэширования целых страниц. `Zend_Cache_Frontend_Page` нельзя использовать для кэширования отдельных блоков.

Идентификатор кэша вычисляется автоматически с использованием `$_SERVER['REQUEST_URI']` и (в зависимости от опций) `$_GET`, `$_POST`, `$_SESSION`, `$_COOKIE`, `$_FILES`. Кроме этого, вы используете только один метод для вызова (`start()`), потому что `end()` вызывается автоматически, когда страница заканчивается.

На данный момент мы планируем добавить условную систему HTTP для сохранения пропускной способности (система будет отправлять HTTP 304 Not Modified, если есть попадание в кэш и броузер уже имеет правильную версию страницы).

### Доступные опции

#### Опции Zend_Cache_Frontend_Page

Опция | Тип данных | Значение по умолчанию | Описание
--- | --- | --- | ---
http_conditional | Boolean | `FALSE` | Использовать условную систему HTTP (не реализовано на данный момент)
debug_header | Boolean | `FALSE` | Если установлен в `TRUE`, то отладочный текст вставляется перед каждой кэшируемой страницей.

default_options

Array

`array(...смотрите далее...)`

Ассоциативный массив опций, включаемых по умолчанию:

- (boolean, true по умолчанию) cache: если `TRUE`, то кэширование включено

- (boolean, false по умолчанию) cache_with_get_variables: если `TRUE`, кэширование включено, даже если в массиве `$_GET` есть переменные

- (boolean, false по умолчанию) cache_with_post_variables: если `TRUE`, кэширование включено, даже если в массиве `$_POST` есть переменные

- (boolean, false по умолчанию) cache_with_session_variables: если `TRUE`, кэширование включено, даже если в массиве `$_SESSION` есть переменные

- (boolean, false по умолчанию) cache_with_files_variables: если `TRUE`, кэширование включено, даже если в массиве `$_FILES` есть переменные

- (boolean, false по умолчанию) cache_with_cookie_variables: если `TRUE`, кэширование включено, даже если в массиве `$_COOKIE` есть переменные

- (boolean, true по умолчанию) make_id_with_get_variables: если `TRUE`, то идентификатор кэша будет зависеть от содержимого массива `$_GET`

- (boolean, true по умолчанию) make_id_with_post_variables: если `TRUE`, то идентификатор кэша будет зависеть от содержимого массива `$_POST`

- (boolean, true по умолчанию) make_id_with_session_variables: если `TRUE`, то идентификатор кэша будет зависеть от содержимого массива `$_SESSION`

- (boolean, true по умолчанию) make_id_with_files_variables: если `TRUE`, то идентификатор кэша будет зависеть от содержимого массива `$_FILES`

- (boolean, true по умолчанию) make_id_with_cookie_variables: если `TRUE`, то идентификатор кэша будет зависеть от содержимого массива `$_COOKIE`

- (int, false по умолчанию) specific_lifetime: если не `FALSE`, то значение этой опции, обозначающей время жизни кэша, будет использоваться для выбранного регулярного выражения

- (array, array() по умолчанию) tags: теги для записи в кэше

- (int, null по умолчанию) priority: приоритет. Действует только если выбранный бэкэнд поддерживает приоритеты.

regexps

Array

`array()`

Ассоциативный массив для установки опций только для некоторых REQUEST_URI. Ключами этого массива являются регулярные выражения (PCRE), значениями — ассоциативные массивы со специальными опциями, которые устанавливаются, если `$_SERVER['REQUEST_URI']` соответствует регулярному выражению (см. default_options в этом списке доступных опций). Если `$_SERVER['REQUEST_URI']` соответствует нескольким регулярным выражениям, то используется только последнее из них.

memorize_headers | Array | `array()` | Массив строк с именами HTTP-заголовков. Перечисленные заголовки будут сохранены в кэше и будут замещены при попадании в кэш.

### Примеры

Использование `Zend_Cache_Frontend_Page` довольно простое:

    // [...]

    $cache->start();
    // если есть попадание в кэш, то результат отправляется броузеру
    // и выполнение скрипта на этом прекращается

    // остальная часть страницы ...

Более сложный пример, показывающий способ создания централизованного управления кэшированием в загрузочном файле (например, для использования с `Zend_Controller`).

    /*
     * Вы должны избегать слишком большого количества строк кода перед этим участком
     * кэша. Например, для наибольшей производительности "require_once" или
     * "Zend_Loader::loadClass" должны находиться после кэшируемого участка
     */

    $frontendOptions = array(
       'lifetime' => 7200,
       'debug_header' => true, // для отладки
       'regexps' => array(
           // кэширование всего IndexController
           '^/$' => array('cache' => true),

           // кэширование всего IndexController
           '^/index/' => array('cache' => true),

           // не кэшируем ArticleController...
           '^/article/' => array('cache' => false),

           // ...но кэшируем действие "view" контроллера ArticleController
           '^/article/view/' => array(
               'cache' => true,

               // кэшируем, даже если есть переменные $_POST
               'cache_with_post_variables' => true,

               // но кэш будет зависеть от массива $_POST
               'make_id_with_post_variables' => true,
           )
       )
    );

    $backendOptions = array(
        'cache_dir' => '/tmp/'
    );

    // получение объекта Zend_Cache_Frontend_Page
    $cache = Zend_Cache::factory('Page',
                                 'File',
                                 $frontendOptions,
                                 $backendOptions);

    $cache->start();
    // если есть попадание в кэш, результат отправляется броузеру,
    // и выполнение скрипта на этом завершается

    // [...] конец загрузочного файла
    // (этот код не исполняется, если есть попадание в кэш)

### Отмена кэширования

В некоторых случаях может потребоваться отменить текущий процесс кэширования - например, если используется код возврата, отличный от HTTP 200. Поэтому мы добавили метод `cancel()`:

    // [...]

    $cache->start();

    // [...]

    if ($someTest) {
        $cache->cancel();
        // [...]
    }

    // [...]