Автор: К.Карпенко 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;
-
-
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
-
<?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
-
<?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:
-
<?php
-
-
include 'connector.php';
-
registerPackage('csc');
-
if(!loadPackages())
-
die('Critical system error !');
-
print $instances['csc']; //В данном случае должен быть возвращён идентификатор ресурса
-
?>
При этом следует заметить, что при реалиацзии механизма создания экземпляра основного класса подключаемых документов, ссылка на класс создаётся лишь раз, а после вызов функции создания просто игнорируется. В целом, я думаю, что на сегодня вполне достаточно, и предлагаю подумать получше об упомянутом в тексте статьи недочёте )
Целую и обнимаю всех кто это читает, успехов вам !
Ваш К.Карпенко, компания ИНПП "Трансфер Новых Технологий - 43"
Эта, и многие другие статьи автора, вы сможете найти по адресу: http://e-code.tnt43.com