Автор: К.Карпенко http://e-code.tnt43.com/
Приветствую всех читающих, ищущих, спотыкающихся и стремящихся рости над собой. Сегодня я бы хотел поразмышлять на тему разработки системы подкючения пакетов функций в рамках платформы PHP. Что же я имею ввиду.
Под пакетами функций, я подразумеваю некоторый набор методов объеденённых относительно семантической зависимости устанавливаемой между ними. Понятие пакета очень хорошо описано в рамках технологии Java, и позволяет создавать более упорядоченные наборы методов, разделяя их относительно их значения и семантики.
Мы же под пакетом будем подразумевать некоторый набор методов и их прототипов (интерфейс класса), зависимых друг от друга по целевому предназанчению.
Структура пакета будет следующей:
packages / {имя_пакета}
class.{имя_пакета}.php
interface.{имя_пакета}.php
errors.{имя_пакета}.php
То есть пакет функций будет разделятся на:
1. Прототипы методов, описанные в рамках интерфейса, описываемого основным классом пакета (идентификатор интерфейса должен соответствовать идентификатору класса, с добавление символа "I", в качестве последнего символа справа в тексте идентификатора)
2. Непосредственная реализация прототипов методов, объявлённых в интерфейсе пакета, в основном классе пакета (идентификатор класса должно соответствовать названию пакета)
3. Информация относительно исключений, которые могут быть возбуждены во время активации того либо иного метода входящего в реализацию основного класса.
Так же, последуюя принципам стандартизации, я считаю необходимым ввести некоторую обязательную структуру для каждого класса, а то есть те его методы и свойства, которые должны в нём присутствовать в любом случае, такой подход очень полезен при модульной структуре информационной системы, и при условии того, что система расширяется не только непосредственными разработчиками, но и третьими лицами. При этом это вводит некую упорядоченность и "чистоту" пакетов функций подключаемых к системе.
Среди обязательных компонентов подключаемого модуля я предпочитаю выделять следующие обязательные составные:
Св-ва:
1. Версия данного пакета
2. Информационный массив об разработчиках пакета
Методы:
1. Основной метод класса, реализующий основную логику класса
2. Функция для получения версии данного пакета (стандарт ООП)
3. Фукнция для получения массива об авторах(е) пакета
Продолжать данный список можно в зависимости от требований к пакету и реализуемых им методах. Заниматся его совершенствованием и корректировкой предстоит вам.
Это была небольшой обзор структурной части системы, теперь же давайте поговорим об подключении и создании экземпляров основных классов непосредственно.
Ниже приведён код для подключения заданных пользователем пакетов, и добавления ссылок на них в ассоциативный массив, в котором будут хранится экземпляры классов. Подход реализован с использованием процедурного программирования, так как в данном случае это будет более универсально и менее проблематично с точки зрения реализации.
<?php
$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;
$packages_to_include[]=$indefier;
}else{
return false;
}
return true;
}
//Функция реализующая непосредственное подключение библиотеки к программе
function includePackage($indefier){
global $instances,$path_to_packages,$package_members;
//Подключить все компоненты пакета
foreach($package_members as $k=>$v){
$member=$path_to_packages.'/'.$indefier.'/'.$v.'.'.$indefier.'.php';
return false;
}else{
if(!include($member))
return false;
}
}
//Добавить экзмепляр класса в коллекцию $instances[]
//Проверка вхождения обязательных компонент в пакет
$err=0;
foreach($main_pieces as $k=>$v){
//Входит ли данный метод в список методов класса
//(проверку вхождения полей добавите сами ;) ).
$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
<?php
define('CONNECTION_ERROR',21
);
define('CONNECTION_SUCCESSFUL',3
);
define('CONNECTION_EXISTS',205
);
define('REQUEST_SUCCESSFUL',2
);
define('INCORRECT_METHOD',31
);
define('CONNECTION_NOT_ESTABILISHED',86
);
?>
Файл: interface.csc.php
<?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;
(eregi('http://',$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)!=''){
foreach($uri as $k=>$v){
$uri[$k]=$v;
}
$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:
<?php
include 'connector.php';
registerPackage('csc');
if(!loadPackages())
die('Critical system error !');
print $instances['csc']; //В данном случае должен быть возвращён идентификатор ресурса
?>
При этом следует заметить, что при реалиацзии механизма создания экземпляра основного класса подключаемых документов, ссылка на класс создаётся лишь раз, а после вызов функции создания просто игнорируется. В целом, я думаю, что на сегодня вполне достаточно, и предлагаю подумать получше об упомянутом в тексте статьи недочёте )
Целую и обнимаю всех кто это читает, успехов вам !
Ваш К.Карпенко, компания ИНПП "Трансфер Новых Технологий - 43"
Эта, и многие другие статьи автора, вы сможете найти по адресу: http://e-code.tnt43.com