PHP система плагинов на основе хуков (hooks)
Здравствуйте, уважаемые читатели блога LifeExample,
сегодня предлагаю затронуть очень редкую тему, информации о которой в
интернете, кране не хватает. Говорить мы будем о том, как самостоятельно
сделать систему плагинов для своей CMS.
Однажды, я где-то читал мысль, что каждый уважающий себя php программист, обязан, хотя бы попробовать сделать свою CMS.
И на самом деле очень много, моих знакомых разрабатывали свои
домашние системы управления сайтом. Вот и я не стал исключением, и сделал собственную CMS, которая в последствии вылилась в обособленный проект MOGUTA.CMS.
MOGUTA.CMS теперь
имеет все задатки, для того, чтобы попытаться покорить сердца начинающих
предпринимателей, дав им возможность комфортно управлять своими
интернет-магазинами. Именно поэтому у меня давно уже зрело желание
создать систему плагинов для своей CMS, да такую чтобы она была легкой и удобной для работы пользователей и программистов.
Проработав некоторое время с движком WordPress, я не мог не оценить его механизм взаимодействия плагинов и ядра, который основан на системе хуков (Hooks – с англ. крючек, зацепка). Опираясь именно на эту концепцию системы плагинов, я решил разработать ее аналог в своей CMS.
PHP hooks – хуки и их концепция
Система хуков как нельзя лучше подходит для расширения функционала
CMS, поскольку позволяет довольно гибко оперировать функциями движка,
меняя их логику и поведение. Поскольку мне не довелось встретить
толкового и обширного объяснения природы плагинов на основе хуков, я попробую изложить ее смысл, настолько – насколько сам его понимаю.
Предлагаю рассмотреть, что такое php hooks, и как их реализовать на простом примере.
В упрощенном виде, система хуков в PHP может выглядеть таким образом:
- Имеется главный класс Main, в котором реализована вся логика приложения.
- Имеется файл plugin.php, содержащий обработчики событий, которые должны произойти классе Main. Например, событием может являться выполнение метода __construct().
- Также есть файл index.php, объединяющий эти два файла в одну систему.
- Запуская index.php инклудом подключается файл plugin.php, и создается экземпляр класса Main.
- В коде метода __construct() класса Main создаются хук (зацепка), для обработчика.
- В момент создания хука, выполняется тело функции из класса файла plugin.php, тем самым изменяя обычное создание экземпляра класса Main.
В общих чертах система хуков именно так и должна работать, но это далеко не все ее возможности. С помощью хуков в php
можно полностью изменить тело функции, в которой был создан хук, а
можно лишь повлиять на результат, перед тем как она его вернет, также
можно передать в исходную функцию другие параметры. Все это позволяет
сделать систему неимоверно гибкой.
Но за такую гибкость приходится платить производительностью системы в целом, поэтому перед реализацией в php системы хуков, советую хорошенько подготовиться теоретически.
Как реализовать Hooks
На самом деле система хуков намного сложнее, чем приведенная ниже,
но на первом этапе знакомства будет вполне достаточно рассмотреть в
миниатюре механизм взаимодействия плагинов и ядра.
Скачать пример реализации системы плагинов ( Скачали: 50 чел. )
В архиве находится три файла:
- index.php – файл запускающий псевдо систему;
- plugin.php – мини плагин;
- libHook.php – библиотека для механизма хуков.
Давайте начнем разбираться с файла index.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?php
//Флаг использования плагинов
$plugin = true;
//подключаем библиотеку для хуков
include 'libHooks.php';
// Инициализация менеджера плагинов, он будет следить за произходящими событиями
$PM = new PM();
//Подключение плагина
if($plugin) {
include 'plugin.php';
}
//псевдо ядро системы
class Core{
public function __construct(){
echo "...Действия ядра...";
// Используем глобальный менеджер плагинов
global $PM;
//Происходит событие demoHook, где-то в недрах ядра
$PM->createHook('demoHook');
echo "...Действия ядра...";
}
}
//Эмуляция запуска ядра системы
$core = new Core(); |
В данном скрипте происходит:
- подключение плагина;
- подключение библиотеки хуков;
- создание менеджера плагинов – экземпляр класса который предназначен для связи плагина с ядром систмы;
- эмуляция запуска дейсвий ядра.
Обратите внимание на конструктор класса Core, в нем происходит инициализаци хука.
Следующая строка, создает действие с именем ‘demoHook’
1
| $PM->createHook('demoHook'); |
Если ранее в плагине был зарегистрирован обработчик данного события, то менеджер плагинов $PM найдет его и выполнит необходимую пользовательскую функцию.
Откроем из архива файл plugin.php
1 2 3 4 5 6 7 8 9
| <?php
//пользовательская функция выполняющаяся при определенном событии
function myFunction(){
echo "<br/> >>>Действия плагина<<< <br/>";
}
//регистрируем пользовательскую функцию как обработчика для события demoHook
$PM->registration(new EventHook('demoHook', 'myFunction')); |
Этот файл представляет собой аналог плагина, в котором имеется функция myFunction(), назначением которой является расширение стандартного функционала системы.
В плагине с помощью системы хуков (hooks) , мы
должны привязать пользовательскую функцию к определенному событию,
которое может произойти в ядре в любой момент и не единожды.
Строка:
1
| $PM->registration(new EventHook('demoHook', 'myFunction')); |
Регистрирует нашу функцию в качестве обработчика, для события demoHook. Теперь когда бы не произошло событие demoHook всегда будет выполнено тело функции myFunction().
Запустив файлы архива, мы увидим такой результат:
Как устроена система хуков
В выше приведенном примере использовалась библиотека для механизма крючков и зацепок, мы подключали ее строкой:
Давайте откроем этот файл и посмотрим, что же в нем хранится, и как все это работает.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| <?php
/**
* Библиотека хуков, содержит интерфейсы PluginManager и Hook,
* а также класс PM и EventHook
* Класс PM предназначен для управления плагинами
* Класс Hook создает обработчик событий
*
* Автор: Авдеев Марк
* Ссылка на описание: http://lifeexampl.nichost.ru/php-primeryi-skriptov/php-sistema-plaginov-na-osnove-hukov-hooks.html
*/
//Интерфейс для слушаемого
interface PluginManager {
function registration(Hook $hook);
function delete(Hook $hook);
function createHook($hookName);
}
//Интерфейс для слушателя
interface Hook {
function run(PluginManager $hookName);
}
// Клас PM (plugin Manager) управляет плагинами,
// регистрирует плагины и устанавливает их взаимодействие с системой.
class PM implements PluginManager{
// Заристрированные обработчики хуков
private $_eventHook;
public function __construct(){
$this->_eventHook = array();
}
// регистрация обработчика для хука
public function registration(Hook $eventHook){
$this->_eventHook[] = $eventHook;
}
// удаление заданного обработчика
public function delete(Hook $eventHook){
if($id = array_search($eventHook, $this->_eventHook, TRUE)){
unset($this->_eventHook[$id]);
}
}
// Если в программе создан hook, сказать об этом всем
// обработчикам, вдруг кто-то из них ждет этого
// хука, для выполнения пользовательсякой функции.
public function createHook($hookName){
foreach($this->_eventHook as $eventHook){
if($eventHook->getHookName() == $hookName){
$eventHook->run($this);
}
}
}
}
//Вешает обработчик для заданного хука
class EventHook implements Hook{
// Наименование хука
private $_hookName;
// пользовательская функция, которая сработает при хуке
private $_functionName;
public function __construct($hookName, $functionName){
$this->_hookName = $hookName;
$this->_functionName = $functionName;
}
// Запуск обработчика для хука
public function run(PluginManager $pm){
if(function_exists($this->_functionName)){
call_user_func($this->_functionName);
}
}
public function getHookName(){
return $this->_hookName;
}
} |
Вся логика взаимодействия хуков с обработчиками основана на паттерне observer,
также известного как "Издатель и Подписчик". Я не буду сейчас описывать
суть данного шаблона проектирования, поскольку делал это ранее.
Смысл заключается в том, что все пользовательские функции
регистрируются для соответствующих действий классом PM в качестве
обработчиков событий-хуков (EventHook).
Когда в системе происходит событие createHook("имя события – хука"),
сгенерированное опять таки классом PM, то он как генератор имеет доступ
к реестру пользовательских функций и начинает подбирать подходящую из
них, для обработки текущего события.
В результате, зарегистрированные на этапе подключения плагинов
функции, могут влиять на поведения любого из стандартных системных
методов, а это полностью удовлетворяет задачу плагинов.
Вывод
Согласитесь, что самостоятельно придумать и спроектировать систему плагинов не простое занятие. Этот материал о системе плагинов и хуков,
который я изложил в данной статье, должен лишь натолкнуть вас на
правильное решение, но не стоит воспринимать его как законченную систему плагинов.
Ну а если вам все же интересно как можно развить данную заготовку до
полноценной системы плагинов, рекомендую ознакомиться с моим движком MOGUTA.CMS, в котором механизм хуков учитывает все атрибуты настоящих плагинов такие как:
- Регистрация плагина в системе;
- Активация плагина;
- Деактивация;
- Изменение результата системной функции;
- Изменение тела системной функции;
- Подмена параметров системной функции.
Также всех желающих разобраться с тем как устроен движок, и помочь в его дальнейшем развитии приглашаю сюда.
Надеюсь эта реализация системы хуков оказалась для вас настолько же интересной как и для меня.
|