Вверх

Блог
RSS лента

Ответить на комментарий

Подход к реализации динамически подключаемых библиотек...

Автор: К.Карпенко http://e-code.tnt43.com/
Приветствую всех читающих, ищущих, спотыкающихся и стремящихся рости над собой. Сегодня я бы хотел поразмышлять на тему разработки системы подкючения пакетов функций в рамках платформы PHP. Что же я имею ввиду.
Под пакетами функций, я подразумеваю некоторый набор методов объеденённых относительно семантической зависимости устанавливаемой между ними. Понятие пакета очень хорошо описано в рамках технологии Java, и позволяет создавать более упорядоченные наборы методов, разделяя их относительно их значения и семантики.
Мы же под пакетом будем подразумевать некоторый набор методов и их прототипов (интерфейс класса), зависимых друг от друга по целевому предназанчению.
Структура пакета будет следующей:
packages / {имя_пакета}
class.{имя_пакета}.php
interface.{имя_пакета}.php
errors.{имя_пакета}.php
То есть пакет функций будет разделятся на:
1. Прототипы методов, описанные в рамках интерфейса, описываемого основным классом пакета (идентификатор интерфейса должен соответствовать идентификатору класса, с добавление символа "I", в качестве последнего символа справа в тексте идентификатора)
2. Непосредственная реализация прототипов методов, объявлённых в интерфейсе пакета, в основном классе пакета (идентификатор класса должно соответствовать названию пакета)
3. Информация относительно исключений, которые могут быть возбуждены во время активации того либо иного метода входящего в реализацию основного класса.

Так же, последуюя принципам стандартизации, я считаю необходимым ввести некоторую обязательную структуру для каждого класса, а то есть те его методы и свойства, которые должны в нём присутствовать в любом случае, такой подход очень полезен при модульной структуре информационной системы, и при условии того, что система расширяется не только непосредственными разработчиками, но и третьими лицами. При этом это вводит некую упорядоченность и "чистоту" пакетов функций подключаемых к системе.
Среди обязательных компонентов подключаемого модуля я предпочитаю выделять следующие обязательные составные:
Св-ва:
1. Версия данного пакета
2. Информационный массив об разработчиках пакета

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

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

  1. <?php
  2.  
  3. $path_to_packages='core/kernel'; //Путь к директории, содержащей библиотеки
  4. $instances=array(); //Массив ссылок на объекты классов
  5. $package_members=array('errors','interface','class'); //Составные пакетов данных
  6. $packages_to_include=array(); //Подключаемые пакеты (данные добавляются по-методу
  7.                         //функции  registerPackage($indefier)
  8.  
  9. function registerPackage($indefier){
  10.     global $path_to_packages,$packages_to_include;
  11.  
  12.     if(file_exists($path_to_packages.'/'.$indefier)){
  13.         $packages_to_include[]=$indefier;
  14.     }else{
  15.         return false;
  16.     }
  17.     return true;
  18. }
  19.  
  20. //Функция реализующая непосредственное подключение библиотеки к программе
  21. function includePackage($indefier){
  22.     global $instances,$path_to_packages,$package_members;
  23.  
  24.     if(trim($indefier)!=''){
  25.         //Подключить все компоненты пакета
  26.         foreach($package_members as $k=>$v){
  27.             $member=$path_to_packages.'/'.$indefier.'/'.$v.'.'.$indefier.'.php';
  28.             if(!file_exists($member)){
  29.                 return false;
  30.             }else{
  31.                 if(!include($member))
  32.                     return false;
  33.             }
  34.         }
  35.         //Добавить экзмепляр класса в коллекцию $instances[]
  36.         if(class_exists($indefier) && !isset($instances[$indefier])){
  37.             //Проверка вхождения обязательных компонент в пакет
  38.             $err=0;
  39.             foreach($main_pieces as $k=>$v){
  40.                 //Входит ли данный метод в список методов класса
  41.                 //(проверку вхождения полей добавите сами ;) ).
  42.                 if(!in_array($v,get_class_methods(get_class($indefier))))
  43.                     $err=1;
  44.                     break;
  45.                 }
  46.             }
  47.             if(!$err)  $instances[$indefier]=new $indefier();
  48.             else return(false);
  49.         }
  50.     }else{
  51.         return false;
  52.     }
  53.     return true;
  54. }
  55.  
  56. //Функция для подключения всех зарегистрированных пакетов
  57. function loadLibs(){
  58.     global $packages_to_include;
  59.  
  60.     foreach($packages_to_include as $k=>$v){
  61.         if(!includePackage($v)){
  62.             return false;
  63.         }
  64.     }
  65.     return true;
  66. }
  67. ?>

Ну вот и всё, как видите всё довольно просто. Хотя в этой реализации есть однин весомый недочёт, и не упомянуть о котором было бы надеждой, что данную статью читает неопытный читатель, либо же просто показать собственное незнание.
Но при написании не подразумевался не тот ни другой случай, а скорее расчитывалось на собственную работу читателя, которая очень положительна в любом случае. Я не буду приводить описания данной проблемы, и не буду приводить её решения, я лишь скажу, что нарушается основной подход к реализации возвращения функцией данных.
Итак, чтобы показать всё это "чудо" на практике приведу пример небольшого класса, который реализует общение с удалённым сервером посредствам сокетов:
Название пакета: csc (Cross Server Communicator)
Файл: errors.csc.php

  1. <?php
  2. define('CONNECTION_ERROR',21);
  3. define('CONNECTION_SUCCESSFUL',3);
  4. define('CONNECTION_EXISTS',205);
  5. define('REQUEST_SUCCESSFUL',2);
  6. define('REQUEST_FAILED',51);
  7. define('INCORRECT_METHOD',31);
  8. define('POINTER_NE',7);
  9. define('CONNECTION_NOT_ESTABILISHED',86);
  10. define('WRONG_DATA',11);
  11. ?>
  12. Файл: interface.csc.php
  13. <?php
  14.  interface cscI{
  15.      private function setPort($port);
  16.     private function  correctMethod($method);    
  17.     public function openConnection($host);
  18.     public function  sendQuery($method,$uri);
  19.     public function  isError($code);
  20.     public function readAnswer($cut_headers=false);
  21.     public function closeConnection();
  22.     public function logon();
  23.  }
  24. ?>
  25. Файл: class.csc.php
  26. <?
  27. class csc implement cscI {
  28.     private $_package=' Cross Server Communication Library';
  29.     private $_version=0.1;
  30.     private $_author=array('company'=>'Transfer of New Technologyes',
  31.                                             'author'=>'K.Karpneko');
  32.     private $_space=" ";
  33.     private  $_crlf="\r\n";
  34.     private  $_host='';
  35.     private  $_port=80;
  36.     private  $_protocol='HTTP/1.1';
  37.     private $_timeout=30;
  38.     private  $_err_str='';
  39.     private  $_err_no=0;
  40.     private  $_answer='';
  41.     private $_errors_codes=array(21,205,51,86,31,11,7);
  42.     private  $_status=200;
  43.     private  $_server_info='';
  44.     private  $_request='';
  45.  
  46.      var $_conn_id=null;
  47.  
  48.     public function setPort($port){
  49.         //Реализация
  50.     }
  51.     public function openConnection($host){
  52.         if(!$this->_conn_id){
  53.             $this->_host=$host;
  54.  
  55.             $this->_conn_id=fsockopen(
  56.                 (eregi('http://',$this->_host)?
  57.                 str_replace('http://','',$this->_host):$this->_host),
  58.                 $this->_port,$this->_err_no,$this->_err_str,
  59.                 $this->_timeout);
  60.             if(!$this->_conn_id){
  61.                 return CONNECTION_ERROR;
  62.             }else{
  63.                 return CONNECTION_SUCCESSFUL;
  64.             }
  65.         }else{
  66.             return CONNECTION_EXISTS;
  67.         }
  68.     }
  69.  
  70.     private function correctMethod($method){
  71.         switch($method){
  72.             case 'POST':
  73.             case 'HEAD':
  74.             case 'GET':
  75.             case 'PUT':
  76.             case 'TRACE':
  77.                 return true;
  78.             default:
  79.                 return false;
  80.         }
  81.     }
  82.  
  83.     public function sendQuery($method,$uri){
  84.         if($this->_conn_id){
  85.             if(trim($method)!='' && trim($uri)!=''){
  86.                 $uri=substr($uri,strpos('?',$uri),strlen($uri));
  87.                 $uri=explode('&',$uri);
  88.                 foreach($uri as $k=>$v){
  89.                     $v=explode('=',$v);
  90.                     $v=$v[0].'='.rawurlencode($v[1]);
  91.                     $uri[$k]=$v;
  92.                 }
  93.                 $uri=implode('&',$uri);
  94.                 $this->_request='';
  95.                 if($this->correctMethod($method)){
  96.                     $this->_request.=$method.$this->_space;
  97.                     $this->_request.=$uri.$this->_space;
  98.                     $this->_request.=$this->_protocol.$this->_crlf;
  99.                     $this->_request.='Host: '.$this->_host.$this->_crlf;
  100.                     $this->_request.='Connection: Close'.$this->_crlf.$this->_crlf;
  101.                     #die($this->_request);
  102.                    $this->_answer=fwrite($this->_conn_id,$this->_request);
  103.                     if($this->_answer){
  104.                         return REQUEST_SUCCESSFUL;
  105.                     }else{
  106.                         return REQUEST_FAILED;
  107.                     }
  108.                 }else{
  109.                     return INCORRECT_METHOD;
  110.                 }
  111.             }else{
  112.                 return WRONG_DATA;
  113.             }
  114.           }else{
  115.               return CONNECTION_NOT_ESTABILISHED;
  116.           }
  117.     }
  118.  
  119.     public  function isError($code){
  120.         return(in_array($code,$this->_errors_codes)?true:false);
  121.     }
  122.  
  123.  
  124.     public function readAnswer($cut_headers=false){
  125.         $this->_result='';
  126.         if($this->_conn_id){
  127.             if($this->_answer){
  128.                 while(!feof($this->_conn_id)){
  129.                     $this->_result.=fread($this->_conn_id,4096);
  130.                 }
  131.                 if($cut_headers){
  132.                     $this->_result=substr($this->_result,0,1024);
  133.                 }
  134.             }else{
  135.                 return POINTER_NE;
  136.             }
  137.         }else{
  138.             return CONNECTION_NOT_ESTABILISHED;
  139.         }
  140.         return $this->_result;
  141.     }
  142.  
  143.     public  function logon(){
  144.         //METHOD NOT IMPLEMENTED
  145.     }
  146.  
  147.     public  function closeConnection(){
  148.         return(isset($this->_conn_id)?fclose($this->_conn_id):CONNECTION_NOT_ESTABILISHED);
  149.     }
  150.  
  151. }
  152. ?>

Далее подразумевается, что функции для динамического подключения были помещены в документ connector.php:

  1. <?php
  2.  
  3.  include 'connector.php';
  4. registerPackage('csc');
  5. if(!loadPackages())
  6.     die('Critical system error !');
  7. print $instances['csc']; //В данном случае должен быть возвращён идентификатор ресурса
  8. ?>

При этом следует заметить, что при реалиацзии механизма создания экземпляра основного класса подключаемых документов, ссылка на класс создаётся лишь раз, а после вызов функции создания просто игнорируется. В целом, я думаю, что на сегодня вполне достаточно, и предлагаю подумать получше об упомянутом в тексте статьи недочёте )
Целую и обнимаю всех кто это читает, успехов вам !
Ваш К.Карпенко, компания ИНПП "Трансфер Новых Технологий - 43"
Эта, и многие другие статьи автора, вы сможете найти по адресу: http://e-code.tnt43.com

Ваша оценка: Пусто Средняя: 3 (7 votes)

Ответить

 
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • Image links with 'rel="lightbox"' in the <a> tag will appear in a Lightbox when clicked on.
  • Image links from G2 are formatted for use with Lightbox2
  • Image links with 'rel="lightshow"' in the <a> tag will appear in a Lightbox slideshow when clicked on.
  • Links to HTML content with 'rel="lightframe"' in the <a> tag will appear in a Lightbox when clicked on.
  • Links to video content with 'rel="lightvideo"' in the <a> tag will appear in a Lightbox when clicked on.
  • Links to inline or modal content with 'rel="lightmodal"' in the <a> tag will appear in a Lightbox when clicked on.

Подробнее о форматировании

Главная | Портфолио | Услуги | Контакты | Блог