Модераторы: skyboy, MoLeX, Aliance, ksnk
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Оптимиз. функционального программирования, или никому не нужный класс 
:(
    Опции темы
zxmaster
Дата 4.2.2006, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 31.1.2006

Репутация: 1
Всего: 1



Линейное программирование в серьезных веб-проектах - это великое зло, особенно когда комметарии не писать smile Функциональный подход это уже хорошо, но тут возникает некоторая проблеммка - правильно вызовать функцию. Все вроде бы нормально, но когда в результате отработки одной функции нужно вызвать другую, а потом и нее третью, а в конце-концов последняя функция должна послать header, но заголовки послали уже до этого, то возникает проблемма (совсем маленькая). В результате всего этого возникает доволно-таки запутанный алгоритм вызова функций, где самому трудно разобраться.

Основу идеи я нашел где-то в сети. В обыкновенный цикл do while($var/*false по умолчанию*/) заключался switch, в результате этого исполняемая функция могла поменять параметры для switch и while и тогда цикл отрабатывал еще один раз и switch выбирал другую функцию. Я пошел немного дальше. В итоге был сделан класс в основе работающий по данному принципу.

Работа класса:
Существует входящий параметр (get или post) который запускает выбор функций, если его нет - обрабатывается функция по умолчанию.
После отработки функция возвращает битовую маску, на основании которой класс решает, что делать дальше. Елси функция не возвращает значения класс считает, что она отработала не правильно и генерирует сообщение об ошибке.

Установление имени входящего параметра просходит при создании класса RUN::RUN(string param_name) /*данная переменная будет искаться в $_REQUEST*/

Класс работает с несколькими видами функций.
1. Стандартная функция
2. Функция по умолчанию
3. Функция обработки текстового сообщения
4. Функция обработки пользовательского сообщения
5. Функция отрабатывающая при определенном запросе

1.
RUN::set_action(string function_name, string param_value) /*имя функции и значение параметра вызывающего ее*/
Прототип вызова стандартной функции function_name($this_action, $new_action, $txt_message) /*$new_action и $txt_message передаются по ссылке */
Описание параметров
$this_action - значение переменной которое сгенерировало вызов функции.
$new_action - новое действие (см. ниже)
$txt_message - текстовое сообщение о результате работы функции (см. ниже)

2.
RUN::set_default(string function_name)
Прототип вызова function_name(void)

3.
RUN::set_log(string function_name)
Прототип вызова function_name(array/string message)

4.
RUN::set_message(string function_name) // пока не доработанно //

5.
RUN::set_raction(string function_name, string param_value)
Прототип вызова function_name(string $rname, string $rvalue, string $txt_message)
$rname - имя параметра который вызвал функцию
$rvalue - значение этого параметра
$txt_message - текстовое сообщение о результате работы функции (см. ниже)

Битовая маска возвращаемых значений (значения можно комбинировать с помощью '|')
RUN_OK - функция отработала нормально
RUN_DEFAULT - После отработки данной функции запустить функцию по умолчанию
RUN_AGAIN - запустить выбор фукции снова ($new_action должен быть установленн в значение не равноте текущему ($this_action))
RUN_LOG - Запустить обработку текстового сообщения от данной фукции сразу после ее выполнения ($txt_message должно быть определено)
По умолчанию функция в результате своей работы может определять $txt_message это сообщение добавляется в общий массив который передается пользовательской фукции, вызываемой в самом конце работы класса.

Что такое RUN::set_raction(string function_name, string param_value)? Это функция, которая отрабатывает перед стандартными функциями RUN::set_action. Обаботка включается тогда, когда во входящих данный присутствует параметр с именем param_value. Сообщения RUN_DEFAULT и RUN_AGAIN от данной функции не обрабатываются.


Зачем нужна функция обработки пользовательского сообщения? Идея проста только первые биты возвращаемые после работы функции используются классом, а остальные можно передавать какому-либо обработчику. Я думаю что последних 16 бит будет вполне достаточно 0xFFFF0000.
Причем можно будет передавать как число, так и маску.

Вот пример роаботы класса

Жду ваших комметариев или пожеланий. Может идею мне подкините

Код

define('RUN_ERROR',0x00000000);
// Function run OK //
define('RUN_OK',0x00000001);
// Run default function //
define('RUN_DEFAULT',0x00000002);
// Run action cycle again //
define('RUN_AGAIN',0x00000004);
// Treat function txt message //
define('RUN_LOG',0x00000008);
// Run user defined message treat function //
define('RUN_MSG',0x00000010);

// USER MESSAGES from 0x0001 //
define('RUN_USER_MSG',0x00010000);


class RUN {

/**
 * Functions that will be run by action
 * @var array
 */
var $functions = array(/*action=>function_name*/);

/**
 * List of function called on request exist
 * @var array
 */
var $request_functions = array(/*param=>function_name*/);

/**
 * Default function name
 * @var string
 */
var $default_f = '';

/**
 * User message treat function
 *
 * @var string
 */
var $umessage_f = '';

/**
 * Message treat function
 * @var string
 */
var $message_f = '';

/**
 * Function run messages 
 * @var array
 */
var $messages_text = array();

/**
 * Name of the requested variable
 * @var string
 */
var $request = '';

/**
 * Action type wich get form request
 * @var string
 */
var $action = '';

/**
 * New action to run
 *
 * @var string

var $new_action = '';
*/

/**
 * Function treat result
 * @var int (mask)
 */
var $result = 0x0;

var $continue = false;

/**
 * Enter description here...
 *
 * @param string $request
 * @return void
 */
function  RUN($request = 'action') {
    $this->request = $request;
}

/**
 * Add action function
 *
 * @param string $action Action name
 * @param string $function Function name
 * @return boolean
 */
function set_action($function, $action){
    if(strlen($action) && function_exists($function)){
        $this->functions[$action]=$function;
        return true;
    }
    else {
        echo "<b>RUN::set_action Error!</b> Function <b>$function</b> is not exist or wrong <b>action</b> param!<br />";
        return false;
    }
}

/**
 * Add default action function
 *
 * @param string $function Default function name
 * @return boolean
 */
function set_default($function) {
    if(function_exists($function)){
        $this->default_f=$function;
        return true;
    }
    else {
        echo "<b>RUN::set_default Error!</b> Function <b>$function</b> is not exist!<br />";
        return false;
    }    
}

/**
 * Add text message treat function
 *
 * @param string $function Default function name
 * @return boolean
 */
function set_log($function) {
    if(function_exists($function)){
        $this->message_f=$function;
        return true;
    }
    else {
        echo "<b>RUN::set_log Error!</b> Function <b>$function</b> is not exist!<br />";
        return false;
    }    
}

/**
 * Add user message treat function
 *
 * @param string $function Default function name
 * @return boolean
 */
function set_message($function) {
    if(function_exists($function)){
        $this->umessage_f=$function;
        return true;
    }
    else {
        echo "<b>RUN::set_message Error!</b> Function <b>$function</b> is not exist!<br />";
        return false;
    }    
}

/**
 * Add user function for calling if request param exist
 *
 * @param string $function Default function name
 * @return boolean
 */
function set_raction($function, $param) {
    if(preg_match('/^[a-zA-Z0-9]+$/',$param) && function_exists($function)){
        $this->request_functions[$param]=$function;
        return true;
    }
    else {
        echo "<b>RUN::set_raction Error!</b> Function <b>$function</b> is not exist or wrong <b>param</b> value!<br />";
        return false;
    }
}

/**
 * Running action cycle 
 *
 */
function go() 
{
    // Check for default function //
    if(!strlen($this->default_f)) {
        echo "<b>RUN::go Error!</b> No default function set!<br />";
        return;
    }
    // Run on request exist functions //
    $text_message='';$this->result = 0;
    foreach ($this->request_functions as $val=>$function) {
        if(isset($_REQUEST[$val])) {
            $this->result = $function($val, $_REQUEST[$val], &$text_message);
            $this->result &= ~RUN_DEFAULT | ~RUN_AGAIN;
            $this->_treat_result('', &$text_message,$val);
        }
    }
    // Get action param //
    $this->action = isset($_REQUEST[$this->request]) && preg_match('/^[a-zA-Z0-9]+$/',$_REQUEST[$this->request])? $_REQUEST[$this->request] : '';
    // Run action cycle //
    do {
        $new_action = ''; $text_message=''; $this->continue = false; $this->result = 0;
        // trying to find action //
        if($this->action!=='' && isset($this->functions[$this->action])) {
            $this->result = $this->functions[$this->action]($this->action, &$new_action, &$text_message);
        }
        else { 
            // Run default function if exist //
            $def = $this->default_f;
            $def();
            break; 
        }
        // Treat function run result //
        $this->_treat_result(&$new_action, &$text_message);
    } while ($this->continue);
    
    // Treat all functions run messages //
    if(count($this->messages_text) && $this->message_f!=='') {
        $msg = $this->message_f; 
        $msg($this->messages_text);
        $this->message_f = array();
    }
}


function _treat_result($new_action, $txt_message, $request_val = '')
{
    
    // Treat text message directly from last function run //
    if($this->result & RUN_LOG) {
        $msg = $this->message_f; 
        $msg($txt_message);
        $txt_message = '';
    }
    
    // Get txt message from last running function//
    if(strlen($txt_message)) {
        $this->messages_text[] = $txt_message;
        $txt_message = '';    
    }
    
    // last function run Error //
    if(RUN_OK&~$this->result) {
        if ($request_val==='')
            echo "<b>RUN Critical Error!</b> Function <b>".$this->functions[$this->action]."</b> fail on action <b>$this->action</b> <br />";
        else 
            echo "<b>RUN Critical Error!</b> Function <b>".$this->request_functions[$request_val]."</b> fail on request value <b>$request_val</b> <br />";

        return;
    }
    // User message treat function run //
    if($this->result& RUN_MSG && strlen($this->umessage_f)) {
        ${$this->umessage_f}($this->result, $this->action);
    }
    
    // Run action cycle again //
    if($this->result&RUN_AGAIN && $this->action !== $new_action) {
        $this->action = $new_action;
        $new_action = '';
        $this->continue = true;
    }
    
    // Running default action //
    if($this->result & RUN_DEFAULT) {
        $this->action = '';
        $this->continue = true;
    }
    

}

};
// Class End //

$run = new RUN('mode'); // Settin up incoming variable name //

$run->set_default('defaultf');
$run->set_log('msg_treat');
$run->set_action('first', 'a');
$run->set_action('second', 'a_');
$run->set_action('third', 'b');
$run->set_raction('on_request', 'id');
$run->go();


function first($this_action, $new_action, $txt_message){
    echo 'first function<br />';
    
    $txt_message = 'Function first message';
    $new_action = 'a_';
    
    return RUN_OK | RUN_AGAIN |RUN_LOG;
}

function second($this_action, $new_action, $txt_message) {
    echo 'Second function<br />';
    
    $txt_message = 'Function second message';
    $new_action = 'b';
    
    return RUN_OK | RUN_AGAIN;
}

function third($this_action, $new_action, $txt_message) {
    echo "Third function run<br />";
    
    $txt_message = 'Function third message';
    
    return  RUN_OK;
}

function defaultf() {
    echo "default function <br/>";
}

function msg_treat($message)
{
    if(is_array($message)) {
        foreach ($message as $msg)
            echo "This is message: $msg <br/>";
    }
    else {
        echo "Your current message is $message <br />";
    }
}

function on_request($rname, $rvalue, $txt_message){
    echo "On request <br />";
    $txt_message = 'ON request function message';
    
    return RUN_OK |RUN_LOG;
}


PM MAIL   Вверх
Mal Hack
Дата 4.2.2006, 15:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 8
Всего: 261



Цитата(zxmaster @ 4.2.2006, 14:27 Найти цитируемый пост)

Все вроде бы нормально, но когда в результате отработки одной функции нужно вызвать другую, а потом и нее третью, а в конце-концов последняя функция должна послать header, но заголовки послали уже до этого, то возникает проблемма (совсем маленькая). В результате всего этого возникает доволно-таки запутанный алгоритм вызова функций, где самому трудно разобраться.

По-моему, просто надо проектировать грамотно и правильно. Все ошибки идут от неправильного проектирования, а если копать глубже - плохо поставленной задачи.
PM ICQ   Вверх
zxmaster
Дата 4.2.2006, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 31.1.2006

Репутация: 1
Всего: 1



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

Это сообщение отредактировал(а) zxmaster - 4.2.2006, 16:03
PM MAIL   Вверх
Mal Hack
Дата 4.2.2006, 18:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 8
Всего: 261



Цитата(zxmaster @ 4.2.2006, 16:02 Найти цитируемый пост)

но обычно глюки возникают когда ты начинаешь расширять прогу.

Да, но это ИМХО, говорит о том, что система изначально была спроектирована не очень хорошо, касательно дальнейшей расширяемости.
Другое дело, когда расширять надо координально...
Цитата(zxmaster @ 4.2.2006, 16:02 Найти цитируемый пост)

А вот этот класс и есть пример правильного проектирования и удобной расширяемости

ИМХО, конечно, но как-то мне кажется, что это ну не то, чтобы лишнее, а, я бы сказал, явно слишком усложненное...
Хотя может я и не до конца понял сути.
PM ICQ   Вверх
beroal
Дата 5.2.2006, 23:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 212
Регистрация: 18.1.2003
Где: Украина

Репутация: нет
Всего: 3



Всё-таки хотелось бы увидеть пример более приближённый к реальности. Например, как это можно применить на сайте? В начале статье вы про это пишете (там где про switch), но как-то очень кратко.
PM WWW   Вверх
zxmaster
Дата 5.2.2006, 23:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 15
Регистрация: 31.1.2006

Репутация: 1
Всего: 1



Товарищи программисты, суть здесь в том, что бы удобно переключать поток вызова функций. Запускать одни функции по алгоритму свича, а другие при наличии определенных входящих параметров (post или get), а может еще и совместить эти две процедуры smile

Кто хочет понять как работает этот класс пусть возмет мой код и попытаеться исполнить его на совоей машине. Причем разбираться в коде я вам советую после строчки // Class End //
Подсказка: в данном случае обработчик реагирует на переменную в post или get под именем "mode" (значения "a" или "b")
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса

Внимание: данный раздел предназначен для решения сложных, нестандартных задач.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Для профи | Следующая тема »


 




[ Время генерации скрипта: 0.0829 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.