Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

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

Автор: К.Карпенко <LoRd1990@gmail.com>
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"

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

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
7.6K
28 мая 2004 года
Jector
2 / / 28.05.2004
+0 / -1
Мне нравитсяМне не нравится
22 августа 2007, 13:30:21
Автор слышал что-нибудь про __autoload(..), spl_ autoload(..), spl_autoload_register(..)?

Тогда загрузка класса (пакета, библиотеки, как угодно назовите) превратится в:

Код:
<?php

$classTest = new classTest();

?>


Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог