Главная » Полезные статьи » Язык PHP » Подход к реализации динамически подключаемых библиотек (классов) на PHP5
Распечатать статью

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

Приветствую всех читающих, ищущих, спотыкающихся и стремящихся рости над собой. Сегодня я бы хотел поразмышлять на тему разработки системы подкючения пакетов функций в рамках платформы PHP. Что же я имею ввиду.

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

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

Структура пакета будет следующей:
packages / {имя_пакета}
class.{имя_пакета}.php
interface.{имя_пакета}.php
errors.{имя_пакета}.php

То есть пакет функций будет разделятся на:
Прототипы методов, описанные в рамках интерфейса, описываемого основным классом пакета (идентификатор интерфейса должен соответствовать идентификатору класса, с добавление символа «I», в качестве последнего символа справа в тексте идентификатора)
Непосредственная реализация прототипов методов, объявлённых в интерфейсе пакета, в основном классе пакета (идентификаторру класса должно соответствовать названию пакета)
Информация относительно исключений, которые могут быть возбуждены во время активации того либо иного метода входящего в реализацию основного класса.

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

Среди обязательных компонентов подключаемого модуля я предпочитаю выделять следующие обязательные составные:

Св-ва:
Версия данного пакета
Информационный массив об разработчиках пакета

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

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

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

Ниже приведён код для подключения заданных пользователем пакетов, и добавления ссылок на них в ассоциативный массив, в котором будут хранится экземпляры классов. Подход реализован с использованием процедурного программирования, так как в данном случае это будет более универсальное и менее проблематичное с точки зрения реализации решение.
$path_to_packages=’core/kernel'; //Путь к директории, содержащей библиотеки
$instances=array(); //Массив ссылок на объекты классов
$package_members=array(‘errors’,’interface’,’class’); //Составные пакетов данных
$packages_to_include=array(); //Подключаемые пакеты (данные добавляются по-методу
//функции registerPackage($indefier)

function registerPackage($indefier){
global $path_to_packages,$packages_to_include;

if(file_exists($path_to_packages.’/’.$indefier)){
$packages_to_include[]=$indefier;
}else{
return false;
}
return true;
}

//Функция реализующая непосредственное подключение библиотеки к программе
function includePackage($indefier){
global $instances,$path_to_packages,$package_members;

if(trim($indefier)!=»){
//Подключить все компоненты пакета
foreach($package_members as $k=>$v){
$member=$path_to_packages.’/’.$indefier.’/’.$v.’.’.$indefier.’.php';
if(!file_exists($member)){
return false;
}else{
if(!include($member))
return false;
}
}
//Добавить экзмепляр класса в коллекцию $instances[]
if(class_exists($indefier) && !isset($instances[$indefier])){
//Проверка вхождения обязательных компонент в пакет
$err=0;
foreach($main_pieces as $k=>$v){
//Входит ли данный метод в список методов класса
//(проверку вхождения полей добавите сами 😉 ).
if(!in_array($v,get_class_methods(get_class($indefier))))
$err=1;
break;
}
}
if(!$err) $instances[$indefier]=new $indefier();
else return(false);
}
}else{
return false;
}
return true;
}

//Функция для подключения всех зарегистрированных пакетов
function loadLibs(){
global $packages_to_include;

foreach($packages_to_include as $k=>$v){
if(!includePackage($v)){
return false;
}
}
return true;
}
?>

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

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

Итак, чтобы показать всё это «чудо» на практике приведу пример небольшого класса, который реализует общение с удалённым сервером посредствам сокетов:

Название пакета: csc (Cross Server Communicator)

Файл: errors.csc.php
define(‘CONNECTION_ERROR’,21);
define(‘CONNECTION_SUCCESSFUL’,3);
define(‘CONNECTION_EXISTS’,205);
define(‘REQUEST_SUCCESSFUL’,2);
define(‘REQUEST_FAILED’,51);
define(‘INCORRECT_METHOD’,31);
define(‘POINTER_NE’,7);
define(‘CONNECTION_NOT_ESTABILISHED’,86);
define(‘WRONG_DATA’,11);
?>

Файл: interface.csc.php
interface cscI{
private function setPort($port);
private function correctMethod($method);
public function openConnection($host);
public function sendQuery($method,$uri);
public function isError($code);
public function readAnswer($cut_headers=false);
public function closeConnection();
public function logon();
}
?>

Файл: class.csc.php
class csc implement cscI {
private $_package=’ Cross Server Communication Library';
private $_version=0.1;
private $_author=array(‘company’=>’Transfer of New Technologyes’,
‘author’=>’K.Karpneko’);
private $_space=» «;
private $_crlf=»\r\n»;
private $_host=»;
private $_port=80;
private $_protocol=’HTTP/1.1′;
private $_timeout=30;
private $_err_str=»;
private $_err_no=0;
private $_answer=»;
private $_errors_codes=array(21,205,51,86,31,11,7);
private $_status=200;
private $_server_info=»;
private $_request=»;

var $_conn_id=null;

public function setPort($port){
//Реализация
}
public function openConnection($host){
if(!$this->_conn_id){
$this->_host=$host;

$this->_conn_id=fsockopen(
(eregi(‘http://’,$this->_host)?
str_replace(‘http://’,»,$this->_host):$this->_host),
$this->_port,$this->_err_no,$this->_err_str,
$this->_timeout);
if(!$this->_conn_id){
return CONNECTION_ERROR;
}else{
return CONNECTION_SUCCESSFUL;
}
}else{
return CONNECTION_EXISTS;
}
}

private function correctMethod($method){
switch($method){
case ‘POST':
case ‘HEAD':
case ‘GET':
case ‘PUT':
case ‘TRACE':
return true;
default:
return false;
}
}

public function sendQuery($method,$uri){
if($this->_conn_id){
if(trim($method)!=» && trim($uri)!=»){
$uri=substr($uri,strpos(‘?’,$uri),strlen($uri));
$uri=explode(‘&’,$uri);
foreach($uri as $k=>$v){
$v=explode(‘=’,$v);
$v=$v[0].’=’.rawurlencode($v[1]);
$uri[$k]=$v;
}
$uri=implode(‘&’,$uri);
$this->_request=»;
if($this->correctMethod($method)){
$this->_request.=$method.$this->_space;
$this->_request.=$uri.$this->_space;
$this->_request.=$this->_protocol.$this->_crlf;
$this->_request.=’Host: ‘.$this->_host.$this->_crlf;
$this->_request.=’Connection: Close’.$this->_crlf.$this->_crlf;
#die($this->_request);
$this->_answer=fwrite($this->_conn_id,$this->_request);
if($this->_answer){
return REQUEST_SUCCESSFUL;
}else{
return REQUEST_FAILED;
}
}else{
return INCORRECT_METHOD;
}
}else{
return WRONG_DATA;
}
}else{
return CONNECTION_NOT_ESTABILISHED;
}
}

public function isError($code){
return(in_array($code,$this->_errors_codes)?true:false);
}

public function readAnswer($cut_headers=false){
$this->_result=»;
if($this->_conn_id){
if($this->_answer){
while(!feof($this->_conn_id)){
$this->_result.=fread($this->_conn_id,4096);
}
if($cut_headers){
$this->_result=substr($this->_result,0,1024);
}
}else{
return POINTER_NE;
}
}else{
return CONNECTION_NOT_ESTABILISHED;
}
return $this->_result;
}

public function logon(){
//METHOD NOT IMPLEMENTED
}

public function closeConnection(){
return(isset($this->_conn_id)?fclose($this->_conn_id):CONNECTION_NOT_ESTABILISHED);
}

}
?>

Далее подразумевается, что функции для динамического подключения были помещены в документ connector.php:
include ‘connector.php';
registerPackage(‘csc’);
if(!loadPackages())
die(‘Critical system error !’);
print $instances[‘csc’]; //В данном случае должен быть возвращён идентификатор ресурса
?>

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

Целую и обнимаю всех кто это читает, успехов вам !

Источник:   codingrus.ru

Вы можете оставить комментарий, или обратную ссылку на Ваш сайт.

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

Похожие статьи