Каркас приложения на PHP 5
Одним из главных обсуждений при планировании разработки Invision Power Board 3.0 было обсуждение необходимости продолжения поддержки PHP 4 продуктом и разработки продукта только под PHP 5. Разработка под PHP 5 имеет множество преимуществ, и мы реально представляем, что применение возможностей из 5-го PHP позволит увеличить безопасность и эффективность IPB. На решение об отказе от PHP 4 так же повлияли и новости PHP Group о прекращении разработки 4-ой версии.
Чтобы увидеть выгоду от использования PHP 5, нужно рассмотреть новую структуру Invision Power Board, которая стала результатом перехода к 5-ке.
Хотя Invision Power Board 1 и 2 были основаны на паттерне ‘front controller’, они не имели реального каркаса, на который бы навешивался код. Близким к такому каркасу был ‘ipsclass’, который являлся супер-классом.
‘ipsclass’ был удобным методом транспортировки различных классов и функций внутри Invision Power Board. Удобным, но не идеальным. Каждый должен был передавать этот супер-класс из класса в класс, попутно указывая PHP 4 передавать его по ссылке. Супер-класс содержал всю базовую функциональность Invision Power Board. Объекты входных данных, пользователи, базы данных содержались в супер-классе наравне с множеством других объектов и функций. Ни один из них не был упорядочен в каком-либо логическом формате.
В итоге мы решили отказаться от ‘ipsclass’ как супер-класса и реализовали паттерн ‘Controller -> Command -> View’. Это позволило нам быстро добавлять новый код и быстро рефакторить (оптимизировать, модифицировать) старый. Паттерн реализован поверх ‘IPS Registry’ (регистр). IPS Registry является синглтоном (класс одиночка), который поддерживает интерфейсы к другим объектам (база данных, запрос, настройки и пользователь). Такая организация позволила нам легко передавать основные данные через различные слои нашего паттерна (каркаса). Остальные функции из ‘ipsclass’ были перенесены в синглтоны:
«IPSLib» – функции, которые не могут быть отнесены к какой-то определенной области;
«IPSText» — функции для работы с текстом (разбор и очистка);
«IPSCookie» — функции по работе с cookie;
«IPSMember» — функции по работе с пользователями (загрузка, сохранение, обработка).
Это позволило сделать ясную структуру с четкими границами для каждого класса одиночки. Использование синглтонов (одиночек) позволило избавить вас от необходимости передачи объектов по ссылке из класса в класс.
А теперь пример:
Так было в IPB 2.3
print $this->ipsclass->input['name'];
$value = $this->ipsclass->settings['board_name'];
$id = $this->ipsclass->member['id'];
$this->ipsclass->input['f'] = 2;
print $this->ipsclass->get_cookie('foo');
$text = $this->ipsclass->txt_alphanumerical_clean( $text );
print $this->ipsclass->class_forums->build_info();
Так стало в IPB 3.0
print $this->request->getField('name');
$value = $this->settings->getSetting('board_name');
$id = $this->member->getProperty('member_id');
$this->request->setField( 'f', 2 );
print IPSCookie::get('foo');
$text = IPSText::alphanumerical_clean( $text );
print $this->registry->getClass('class_forums')->build_info();
Заметим, что мы реализовали интерфейс ArrayAccess для нашего регистра, так что вы сможете работать с ним еще и так:
print $this->request['name'];
$this->settings['board_name'];
В коде выше используются $this->request, $this->member, стоит понимать, что внутри класса эти атрибуты устанавливаются в конструкторе. Ниже типичный пример такого конструктора.
function __construct( ipsRegistry $registry )
{
$this->registry = $registry;
$this->member = $registry->member();
$this->request = $registry->request();
$this->settings = $registry->settings();
$this->DB = $registry->DB();
}
Так же вы можете обратиться к регистру и напрямую, хотя это настоятельно не рекомендуется делать:
print ipsRegistry::instance()->request()->getField('name');
Теперь вы можете создавать цепочки функций. Это позволяет создавать следующие красивые конструкции:
Так было в IPB 2.3
$this->ipsclass->load_template('skin_boards');
print $this->ipsclass->compiled_templates['skin_boards']->board_index( $data );
Так стало в IPB 3.0
print $this->registry->getClass('output')->getTemplate('boards')->board_index($data);
Как вы можете заметить, вам больше не надо явно загружать шаблон. Он будет загружен функцией ‘getTemplate’, если это еще не было сделано ранее. Затем объект шаблона будет возвращен функцией обратно и по цепочке будет вызван метод ‘board_index()’ этого объекта. Такое простое упорядочение позволит писать меньше кода и сократит пространство для возникновения ошибок.
Мы нашли удачное применение абстрактным классам и интерфейсам, появившимся в 5-ой версии, для определения расширяемых классов. Это позволит другим разработчикам намного проще создавать дополнения к Invision Power Board.
Структура ‘controller -> command’ позволит вам добавлять новые модули и секции без каких-либо изменений в существующих файлах приложения. Разработчику модификаций достаточно будет создать новую папку с модом, а IP.Board сам запустит ее. Принцип работы структуры достаточно прост: контроллер получает переменные из URL и безопасно загружает управляющий (command) файл, если он найден. Например, адрес «appcomponent=core&module=global§ion=login» заставит контроллер подключить управляющий файл «applications/core/modules_public/global/login.php». Для уменьшения риска подделки управляющего файла мы ввели специальную проверку таких файлов с использованием механизма Reflections в IP.B.
На данный момент мы рассмотрели только верхушку айсберга, но уже сейчас должно быть понятно, что каркас 3-ей версии Invision Power Board будет очень мощным и эффективным. И создание такой структуры стало возможно только лишь благодаря полному переходу к PHP 5, чьи возможности мы использовали на полную катушку.