ГлавнаяСтатьиПрограммирование → плагины на php в стиле ООП
плагины на php в стиле ООП E-mail
User Rating: / 0
PoorBest 
Written by xternalx   
Monday, 26 January 2009 17:15

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

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

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

Назовем этот класс PluginManager(class.pluginmanager.php):

include('class.codeplugin.php');
class PluginManager
{
 var $pluginsDir;
 var $pluginsCollection = array();
 
 function PluginManager($dir)
 {
 $this->pluginsDir=$dir;
 $this->initialize();
 }
 
 function registerPlugin($newplugin)
 {
 foreach($this->pluginsCollection as $plugin)
 {
 if($plugin->name==$newplugin->name)
 return false;
 }
 array_push($this->pluginsCollection,$newplugin);
 }
 
 function executeCodePlugins(array $params)
 {
 foreach($this->pluginsCollection as $plugin)
 {
 $plugin->render($params);
 }
 }
 
 function free()
 {
 foreach($this->pluginsCollection as $plugin)
 unset($plugin);
 }
 
 function initialize()
 {
 $r=opendir($this->pluginsDir);
 $i=0;
 //производим поиск файлов
 while (false != ($file = readdir($r)))
 {
 if($file!="." && $file!="..")
 {
 //инклудим найденный файл
 include($this->pluginsDir.$file);
 //отделяем расширение файла от его имени
 $pName = substr($file,0,strpos($file,"."));
 //а вот здесь интересно, создаем экземпляр какого то класса, имя которого
 //хранится в переменной $pName
 $plugin = new $pName();
 $this->registerPlugin($plugin);
 $i++;
 }
 }
 closedir($r);
 return $i;
 }
}

метод PluginManager($dir) является конструктором класса и в качестве параметра принимает строку, в которой указан путь до директории с плагинами.

метод Initialize() инициализирует объект класса PluginManager и загружает все плагины, найденные в директори, указанной в качестве параметра конструктору класса.

метод RegisterPlugin() регистрирует каждый плагин, занося его в отдельный список $pluginsCollection

метод ExecuteCodePlugins(array $params) выполняет все плагины, зарегистрированные в плагиновой системе. в качестве параметра принимает массив параметров(тут могут быть данные из конфига, либо какие то сторонние данные).

Теперь посмотрите самую первую строчку кода из приведенного листинга выше. в файле class.codeplugin.php содержится описание базового класса плагина, реализующего интерфейс для взаимодействия менеджера плагинов с загруженными плагинами. Ниже приведу описание класса:

class CodePlugin
{
 public $name="";
 public $version="";
 public $author="";
 public $url="";
 public $info="";
 public $type="code";

 function CodePlugin()
 {
 return array('name'=>$this->name,
 'type'=>$this->type,
 'version'=>$this->version,
 'author'=>$this->author,
 'url'=>$this->url,
 'info'=>$this->info);
 }
 
 function render(){}
}

Как видите, здесь все очень просто, при создании объекта класса CodePlugin возвращается информация о плагине. Здесь можно добавить любые данные, к примеру массив зависимостей, без которых плагин работать не будет.

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

Сейчас необходимо создать какой нибудь плагин. Обратите внимание, имя файла, в котором описывается плагин должно соответствовать имени класса плагина. Т.е., например, в моем случае я создал класс draw, имя файла плагина соответственно, будет называться draw.php (помните, в методе PluginManager::Initialize() происходило отделение имени файла от расширения? :)).

Наш плагин добавит в движок возможность рисования прямых отрезков. Ниже приведу его код:

class draw extends CodePlugin
{
 public $name="Draw library";
 public $version="0.1b unstable";
 public $author="xternalx";
 public $url="http://xternalx.7pe.net/";
 public $info="";
 public $priority=10;
 
 function draw()
 {
 return array('name'=>$this->name,
 'version'=>$this->version,
 'author'=>$this->author,
 'url'=>$this->url,
 'info'=>$this->info);
 }
 
 function render(array $params)
 {
 //проверяем, удовлетворяет ли переданная строка шаблону. Если да, то производим некоторые модификации
 //юзербара
 if(preg_match_all('/\\[line\\(([0-9]+),([0-9]+),([0-9]+),([0-9]+),(.*)\\)\\]/i', $params['code'], $regs))
 {
 //hexToRGB - произвольная функция, которая раскладывает цветовой индекс из hex в массив значений R, G, B
 $rgb=hexToRGB($regs[5][0]);
 $c=ImageColorAllocate($img,$rgb[0],$rgb[2],$rgb[4]);
 //рисуем полосу на юзербаре
 imageline($params['userbar'],$regs[1][0],$regs[2][0],$regs[3][0],$regs[4][0],$c);
 //удаляем код линии из кода юзербара
 $text=preg_replace('/\\[line\\(([0-9]+),([0-9]+),([0-9]+),([0-9]+),(.*)\\)\\]/i',"",$params['code']);
 }
 }
}

Как видите, здесь в принципе, нет ничего сложного. При помощи регулярных выражений произвожу парсинг строки, разделяя ее на части. В элемент массива $params['userbar'] содержит в себе ссылку на графический контекст юзербара, в котором происходит рисование, а так же $params['code'] хранит ссылку на текст юзербара для проведения различного рода манипуляций над ним.

Для того чтобы заставить наши плагины выполняться, где то в коде движка вставляем такие строки:

$manager = new PluginManager($cfg['pluginsdir']);
$params = array('userbar'=>&$img,
 'code'=>&$text,
 'config'=>&$cfg);
$manager->executeCodePlugins($params);
$manager->free();
unset($manager);

Здесь создается экземпляр класса PluginManager, после чего он выполняет все "известные" ему плагины, передавая каждому из них какие либо параметры, после этого освобождает память, занятую плагинами, и происходит удаление самого экземпляра $manager.

Вот в принципе и все, я привел самый простой пример, который при наличии фантазии и определенных навыков можно развивать до бесконечности :))

Хочу сказать сразу, данный код не является оптимизированным, и наверняка, php программисты со стажем найдут в нем уйму мест, которые можно было бы неплохо оптимизировать. Да я и не мечу в профессионалы, я просто занимаюсь своим хобби - изучаю новое...

Жду Ваших вопросов, критики, и прочих пожеланий...

Last Updated on Thursday, 15 July 2010 23:10
 

Comments  

 
0 # mazx 2010-07-15 11:30
Хоть чето внятное нашел :)
Reply | Reply with quote | Quote
 
 
0 # xternalx 2010-07-15 23:09
Самое главное, из конструктора плагина ничего не нужно возвращать, Ведь подразумевается что возвращается экземпляр этого класса :)
Reply | Reply with quote | Quote
 

Add comment


Security code
Refresh