PHP

PHP система плагинов на основе хуков (hooks)

Здравствуйте, уважаемые читатели, сегодня предлагаю затронуть очень редкую тему, информации о которой в интернете, кране не хватает. Говорить мы будем о том, как самостоятельно сделать систему плагинов для своей 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

На самом деле система хуков намного сложнее, чем приведенная ниже, но на первом этапе знакомства будет вполне достаточно рассмотреть в миниатюре механизм взаимодействия плагинов и ядра.

Давайте начнем разбираться с файла index.php
<?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’
$PM->createHook('demoHook');

Если ранее в плагине был зарегистрирован обработчик данного события, то менеджер плагинов $PM найдет его и выполнит необходимую пользовательскую функцию.

Откроем из архива файл plugin.php
<?php

//пользовательская функция выполняющаяся при определенном событии
function myFunction(){
  echo "<br/> >>>Действия плагина<<< <br/>";
}

//регистрируем пользовательскую функцию как обработчика для события demoHook
$PM->registration(new EventHook('demoHook', 'myFunction'));

Этот файл представляет собой аналог плагина, в котором имеется функция myFunction(), назначением которой является расширение стандартного функционала системы.

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

Строка:
$PM->registration(new EventHook('demoHook', 'myFunction'));

Регистрирует нашу функцию в качестве обработчика, для события demoHook. Теперь когда бы не произошло событие demoHook всегда будет выполнено тело функции myFunction().

Запустив файлы архива, мы увидим такой результат:



Как устроена система хуков

В выше приведенном примере использовалась библиотека для механизма крючков и зацепок, мы подключали ее строкой:
include 'libHooks.php';

Давайте откроем этот файл и посмотрим, что же в нем хранится, и как все это работает.
<?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, то он как генератор имеет доступ к реестру пользовательских функций и начинает подбирать подходящую из них, для обработки текущего события.

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

Вывод

Согласитесь, что самостоятельно придумать и спроектировать систему плагинов не простое занятие. Этот материал о системе плагинов и хуков, который я изложил в данной статье, должен лишь натолкнуть вас на правильное решение, но не стоит воспринимать его как законченную систему плагинов.

Надеюсь эта реализация системы хуков оказалась для вас настолько же интересной как и для меня.
Теги:
плагин, хук, hooks
Добавлено: 26 Сентября 2013 01:39:33 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...