Объявление

Хотите приглашение на сайт? Пишите: niikto@samovarchik.info


 

Во внутреннем устройстве движка FluxBB.PE довольно заметную роль играет класс Pe.
Основное его предназначение - это инициализация и выдача ресурсов по запросу. Типы ресурсов любые - числа, строки, массивы любой сложности, объекты и прочее. Примеры возвращаемых ресурсов - массив параметров конфигурации сайта, объект базы данных, парсер, шаблонизатор и т.д.

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

Данное руководство расскажет с точки зрения программиста, как пользоваться классом Pe и настраивать правила инициализации объектов.

Класс Pe был получен от artoodetoo и используется c некоторыми дополнениями.

Оглавление:

  1. Введение

  2. Автозагрузка классов

  3. Обработка исключений

  4. Помещение данных в реестр

  5. Извлечение данных из реестра

  6. Конфигурирование реестра

  7. Файлы конфигурации

  8. Правила инициализации

Введение

Класс Pe определяется в файле protected/pebase.php
Класс статический, т.е. нет необходимости создавать экземпляры класса, для того, чтобы пользоваться его функционалом.

В момент подключения класса (include/require) автоматически производится первичная инициализация - вызывается метод Pe::init(). В этот момент происходит вычисление пути к корню движка (в дальнейшем это значение можно получить при помощи Pe::get('root')), назначение класса Pe как обработчика автозагрузки классов и обработчика исключений.
Класс защищен от повторной инициализации - все последующие вызовы Pe::init() игнорируются.

В абсолютном большинстве случаев вам не придется заботиться о подключении и инициализации класса Pe. Все скрипты движка в начале своего выполнения подключают файл protected/bootstrap.php, в начале которого происходит подключение protected/pebase.php и дальнейшее конфигурирование класса Pe. (Подробнее о конфигурировании читайте ниже.)

Автозагрузка классов

Класс Pe осуществляет автозагрузку классов.
Это значит, что для использования какого-либо класса, вам не нужно его предварительно подключать с помощью include/require.
Если файл с классом лежит в директории protected/ и имя файла совпадает с именем класса, записанным всеми маленькими буквами, то Pe автоматически найдет и подключит такой файл.

Например, файл protected/myclass.php:

<?php
class MyClass { ... }

При выполнении кода:

$mc = new MyClass();

если класс с именем MyClass не существует, PHP обращается к классу Pe, чтобы тот обработал автозагрузку (метод Pe::_handleClass()), при этом ему передается имя класса. Pe преобразует это имя так, чтобы оно содержало только строчные буквы, после чего проверяет существование файла protected/myclass.php. Если такой файл существует, он будет подключен. В противном случае выбрасывается исключение.

Обработка исключений

При возникновении исключения, управление передается методу Pe::handleException(), который делегирует обработку исключения классу ErrorHandler. Класс ErrorHandler является оберткой над модифицированной функцией error() из FluxBB 1.4, и описание этого класса выходит за рамки статьи.

Помещение данных в реестр

В реестре класса Pe могут храниться именованные данные различной природы (числа, строки, массивы, объекты).

Для ручного помещения данных в реестр используется метод Pe::set(). Первым параметром передается имя, по которому будут доступны данные, вторым - сами данные. Если данные с указанным именем уже существуют в реестре, они будут замещены новыми.

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

Pe::set('digit', 42);
Pe::set('string', 'Hello, World!');
Pe::set('list', array(1, 2, 3, 4, 5));
Pe::set('myclass', new MyClass());

На имена хранимых данных не накладывается каких-либо ограничений, но в большинстве случаев удобнее, если они удовлетворяют требованиям PHP по именованию переменных.

Извлечение данных из реестра

Извлечение данных из реестра выполняется методом Pe::get(), которому параметром передается имя извлекаемого ресурса.

Извлечение данных является более сложным процессом:

  1. Если данные с указанным именем существуют в реестре, они извлекаются и возвращаются методом.

  2. Если данных нет, проверяется набор правил инициализации на предмет наличия там правила для указанного имени ресурса. (О правилах читайте ниже). При наличии правил, данные инициализируются, сохраняются в реест с нужным именем и возвращаются методом.

  3. Если 1 и 2 условия не выполняются, метод возвращает null

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

$pun_config = Pe::get('pun_config');

Что происходит в этой строке? Предположим, что ранее Pe::get('pun_config') не вызывалось и Pe::set('pun_config', ...) тоже никто не делал. Тогда, в соответствии с текущими настройками движка, происходит следующее:

  • Класс Pe не находит в реестре записи с именем 'pun_config' и обращается к списку правил.

  • В списке правил инициализации находится запись, которая указывает, что 'pun_config' можно получить из кэша с помощью класса CacheLoader и его метода getData. Если быть более точным, то там содержится только имя некоторого ресурса, который тоже должен храниться в реестре, и его метод. К какому классу принадлежит ресурс, какого типа данные вернет его метод и откуда эти данные получены, классу Pe неважно.

  • Класс Pe ищет в реестре объект с именем 'cacheLoader' (так записано в правилах инициализации). Предположим, что не находит.

  • Класс Pe ищет правила инициализации для объекта 'cacheLoader'. Здесь-то как раз и указано, что этот объект принадлежит классу CacheLoader, а также указано, какие параметры необходимо передать конструктору класса. Объект создается.

  • В этот момент, где-то между new и ; срабатывает автозагрузка и подключает php-файл с исходным кодом класса CacheLoader.

  • Созданный объект сохраняется в реестре под именем 'cacheLoader'. При следующем обращении к нему, уже не придется его создавать.

  • Вызывается метод getData() которому в качестве параметра передается имя того, что нужно извлечь из кэша. Предположим, что конфигурация уже была ранее помещена в кэш. В противном случае внутри метода getData() был бы вызов Pe::get('cacheGenerator')->generateConfigCache(), который извлекает конфиг из базы данных и сохраняет в кэше. (В качестве упражнения, можете построить последовательность действий, которая при этом произошла бы).

  • Данные о конфигурации сохраняются в реестр под именем 'pun_config' и при следующем обращении будут взяты уже оттуда.

  • Полученные данные возвращаются методом get() и сохраняются в переменной $pun_config.

Далее будет описано как настроить Pe на выполнение всего этого.

Конфигурирование реестра

Рассмотренный ранее метод Pe::set() позволяет загружать только один именованный элемент данных, загружаемые данные при этом должны быть уже инициализированы. Но что если мы хотим загрузить сразу большое количество именованных данных или вообще снять с себя необходимость каждый раз вручную инициализировать некоторые из них?

На этот случай в классе Pe предусмотрено конфигурирование реестра. Оно выполняется методом Pe::config(). В качестве параметра этому методу передается массив следующего вида:

array(
    'rules' => array( ... ),

    'name1' => %value1%,
    'name2' => %value2%,
    ...
    'nameN' => %valueN%
)

Где name1, ..., nameN - это произвольные имена, которые вы сами выбираете для ваших данных. Как уже упоминалось выше, на имена не накладывается каких-либо ограничений, но в большинстве случаев желательно, чтобы они удовлетворяли требованиям PHP по именованию переменных. Если вы не планируете использовать эти данные для инициализации других данных или объектов, то подойдут любые символы, которые можно напечатать на клавиатуре. Но в правилах инициализации можно использовать ссылки на другие элементы реестра только если их имена удовлетворяют ограничениям. %value1%, ..., %valueN% - произвольные значения, которые позже будут помещены в реестр.

'rules' - это особый элемент конфигурационного массива, который задает правила для инициализации данных.
Он подробнее будет рассмотрен ниже.
Здесь же отмечу, что сам этот элемент в реестр не помещается. Т.е. Pe::get('rules') вернет null. Если поместить элемент с таким именем в реестр через Pe::set('rules', ...), то это не добавит новых правил для инициализации, а сами данные, передаваемые в метод set(), будут помещены в реестр в том виде, как вы их передали.

Файлы конфигурации

Файлы конфигурации движка хранятся в директории protected/config/

Из себя они представляют обычный PHP-файл, единственным предназначением которого является создание и возврат конфигурационного массива, описанного ранее.
Почему я говорю именно "создания", а не, например, "хранения"?. Дело в том, что ничто не мешает нам конструировать такой массив динамически.
Пример из protected/config/main.php:

// {$start} is set in protected/bootstrap.php
'pun_debug' => defined('PUN_DEBUG') ? array('component' => 'punPage', 'method' => 'getPunDebug', 'start' => '{$start}') : null,
'saved_queries' => defined('PUN_SHOW_QUERIES') ? array('component' => 'punPage', 'method' => 'getSavedQueries') : null,

При необходимости, логика создания конфигурационного массива может быть и более сложной.

Файлы конфигурации движка имеют следующую структуру:

<?php
return array(
'rules' => array(
    ...
    ),
...
);

А использовать их можно следующим образом:

Pe::config(include(Pe::get('root') . 'protected/config/main.php'));

На данный момент в движке используются только три файла конфигурации:

  • protected/config/main.php - основные настройки и правила инициализации для движка. Здесь вы найдете 98% настроек и правил используемых при повседневной работе скриптов.

  • protected/config/config.php - этот файл создается после установки и содержит те же самые данные, что и config.php в FluxBB ветки 1.4. Например, там хранится пароль от базы данных.

  • protected/config/install.php - версия конфигурации, используемой во время установки движка. После установки можете смело удалить этот файл, он больше не понадобится.

Еще небольшая часть конфигурации задается методом Pe::set() в protected/bootstrap.php. Например, там можно увидеть такие строчки:

// Define standard date/time formats
Pe::set(
    'forum_time_formats',
    array($pun_config['o_time_format'], 'H:i:s', 'H:i', 'g:i:s a', 'g:i a')
);
Pe::set(
    'forum_date_formats',
    array($pun_config['o_date_format'], 'Y-m-d', 'Y-d-m', 'd-m-Y', 'm-d-Y', 'M j Y', 'jS M Y')
);

Правила инициализации в файлах конфигурации сгруппированы по их назначению, каждая такая группа подписана.

Список секций (групп)
  • DataBase section - работа с базой данных.

  • User section - пользователь и все что с ним связано (cookies, пометка тем прочитанными).

  • Cache section - работа с кэшем (генерация кэша редко изменяемых, но часто требуемых данных, получение данных из кэша).

  • Language section - работа с языковыми файлами.

  • Template section - шаблонизатор и то, что с ним связано.

  • Parser - парсер.

  • File upload - класс FileUpload.

  • Controllers - тут собраны все классы-контроллеры (см. модель MVC).

  • Несколько правил, которые не подходят под другие категории.

  • Группа правил, которые в FluxBB ветки 1.4 определялись через if (!defined(...)) define(...); в include/common.php.

В конфигурационных файлах присутствуют также и просто данные. Их не так много, если сравнивать с количеством строк, занятого правилами инициализации.
Например, там определяются такие константные значения, как виды контента (kind), требуемая ревизия базы данных, виды пользователей (админ, модератор, гость и т.д.) и прочее.

Правила инициализации

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

Элемент 'rules' является массивом, структура которого напоминает структуру самого конфигурирующего массива:

Pe::config(array(
    'rules' => array(
        'name1' => %value1%,
        ...
        'nameK' => %valueK%
    ),
    ...
));

name1, ..., nameK - произвольные имена, которые вы задаете для правил. Впоследствии это будут имена элементов данных в реестре. Т.е. правило для Pe::get('pun_config') должно иметь имя 'pun_config', иначе класс Pe не найдет правило и вернет null. %value1%, ..., %valueK% - либо особым образом параметризованная строка, либо массив определенной структуры.

Параметризованные строки

Пример параметризации строки:

'forum_cache_dir' => '{$root}cache/',

На моем компьютере вызов Pe::get('forum_cache_dir'); вернет "/var/www/flux/pe/cache/".

Параметр задается при помощи открывающей фигурной скобки {, имени переменной (знак $ + имя элемента данных в реестре) и закрывающей фигурной скобки }. Это похоже на то, как можно средствами PHP параметризовать строку в двойных кавычках:

$a = 'Hello';
$b = 'World';
$str = "{$a}, {$b}!";    // "Hello, World!"

В нашем же случае кавычки используются одинарные, чтобы не пришлось экранировать символы с особым значением. И сама интерпретация параметров у нас происходит не в момент когда строка объявляется, а намного позже - при первом использовании строки (перед возвращением из Pe::get() или перед передачей в качестве параметра конструктору класса или методу (подробнее см. ниже)).

Параметров в строке может быть несколько.

  • Если в строке нет ни одного параметра, она возвращается в неизменном виде.

    ...
    'str' => 'Just a string.',
    ...
  • Если присутствует только один параметр и кроме параметра нет больше ни одного символа, будет предпринят поиск в реестре по имени параметра, и вместо строки будет возвращены хранящиеся под этим именем данные в том виде, как они хранятся. Т.е. это вполне может быть объект или массив.

    ...
    'rootDir' => '{$root}',
    'db' => '{$db}',
    ...

    Сейчас строки вида 'db' => '{$db}' могут показаться бессмысленными, и действительно, вне контекста такая строчка является даже ошибочной. Такой подход в основном использется при описании параметров, передаваемых конструктору класса.
    Другая строчка примера - 'rootDir' => '{$root}' - по сути задает псевдоним для элемента данных с именем 'root'.

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

    ...
    'a' => 'Hello',
    'b' => 'World',
    'str' => '{$a}, {$b}!',    // 'Hello, World!'
    ...

Инициализация объектов

Пример правила для инициализации объекта:

'langLoader' => array('class' => 'LangLoader',
    'rootDir' => '{$root}',
    'pun_user' => '{$pun_user}'),

Вызов Pe::get('langLoader'); вернет инициализированный объект класса LangLoader.

Наверное массив, стоящий справа от 'langLoader' => показался вам очень знакомым. Действительно, он имеет ту же структуру, что и конфигурационный массив, с той только разницей, что "особым" элементом теперь является 'class', который указывает, какой класс нужно использовать. Все остальные элементы будут переданы конструктору класса параметром-массивом. При этом все параметризованные строки в этом массиве будут обработаны в соответствии с правилами, описанными выше.

Получение доступа к параметрам

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

public function __construct(array $params)
{
    echo $params['rootDir'] . "\n";
    echo ($params['pun_user']['is_guest'] ? 'Гость' : 'Не гость') . "\n";
}

или так:

public function __construct(array $params)
{
    extract($params);
    echo $rootDir . "\n";
    echo ($pun_user['is_guest'] ? "Гость" : "Не гость") . "\n";
}

Если же вы наследуетесь от PeComponent, то его конструктор автоматически сохраняет переданные ему параметры в качестве полей объекта, с именами, совпадающими с ключами в массиве правила инициализации. Вы можете заранее определить для них уровень доступности (в противном случае, они будут объявлены как public):

class MyClass extends PeComponent
{
    protected
        $rootDir, $pun_user;

    public function printVars()
    {
        var_dump($this->rootDir, $this->pun_user);
    }
}

Если обобщить все выше сказанное, то вызов $ll = Pe::get('langLoader'); равносилен следующей конструкции:

require Pe::get('root') . 'protected/langloader.php';    // Не забыли про автозагрузку классов?
$ll = new LangLoader(array(
    'rootDir' => Pe::get('root'),
    'pun_user' => Pe::get('pun_user')
));
Pe::set('langLoader', $ll);

Данные, возвращаемые методом объекта

Вернемся к примеру с CacheLoader и $pun_config (см. выше в описании Pe::get()), вот строчка из protected/config/main.php:

'pun_config' => array('component' => 'cacheLoader', 'method' => 'getData', 'data' => 'config'),

Ключевыми являются элементы 'component' и 'method'. Первый указывает имя объекта в реестре, второй метод этого объекта. Все остальные элементы передаются в виде массива этому методу. Слово 'component' как бы предполагает, что объект принадлежит классу, унаследованному от PeComponent. И на самом деле, все подобные объекты в движке унаследованы от PeComponent. Но использовать объекты любого другого класса не запрещается. В случае, если элемент реестра не является объектом, или у него нет метода с указанным именем, будет выброшено исключение.

В упрощенном виде вызов $pun_config = Pe::get('pun_config'); можно представить следующим образом:

$component = Pe::get('cacheLoader');
$pun_config = $component->getData(array('data' => 'config'));
Pe::set('pun_config', $pun_config);
 

Дизайн сайта отсутствует
оформление: Группа «САМОВАРчик»

[ Сгенерировано за 0.015 сек, 8 запросов выполнено - Использовано памяти: 1.93 MiB (Пик: 2.01 MiB) ]