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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Прервать скрипт и продолжить на следующем запуске, Подпроблема: отсутствие GOTO в PHP 
:(
    Опции темы
maxbrown
Дата 16.6.2008, 10:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



Задача: при наступлении некоего if($condition) корректно прервать работу некоего PHP-скрипта, а при следующем запуске (возможно, через несколько недель) возобновить с той же точки.

Начатое решение: написана функция save_variables(), которая при вызове с параметром - именем переменной - регистрирует эту переменную у себя в static-массиве, а при вызове без параметров сохраняет все переменные, заявленные ей при предыдущих обращениях, в xml-файл и вносит запись о нём в MySQL-базу.
Прерывание реализуется в виде заключения всего скрипта в некую функцию MyMain(), в которой в нужном месте вставляется:
if ($condition) return save_variables();
Функция обратной заргузки сохранённых переменных пока не написана, но проблем с этим нет.
А вот, с чем проблема есть:

Проблема: Я не могу придумать элегантного решения для возврата в точку прерывания (было бы здорово использовать GOTO, но в PHP нет GOTO) и прошу помощи Клуба.

UPD1: Предложены решения на основе паттерна State, суть которых сводится к модификации всех операторов ветвления/цикла в скрипте, чтобы в зависимости от наличия/отсутствия точки сохранения (она же "метка", она же "запись состояния") они либо выполнялись, либо пропускались скриптом на пути к нужной метке. Недостаток: по сути, это требует как минимум синтаксического анализа всего скрипта, что практически не поддаётся автоматизации.

Пояснение: преобразованию в "прерывабельно-возобновибельные" подлежит заранее неизвестное большое количество заранее неизвестных скриптов на PHP.

UPD2: Обсуждается вариант решения на posix_getpid и posix_kill


WBR - Max Brown
www.Wgent.com/kontakty.htm
www.ObBot.com/contact.htm
mail: "Max Brown <[email protected]>" (присутствие имени в поле To: обязательно!)
ICQ: 6654627 (при запросе на ауторизацию указание причины обязательно!)
Моб: +7-960-5213199 (Билайн)

P.S. Приветствуются любые варианты (идеи, подсказки, в какую сторону копать), в том числе через команды Linux/Apache/PHP5.

Это сообщение отредактировал(а) maxbrown - 17.6.2008, 23:14
PM MAIL WWW ICQ   Вверх
Feldmarschall
Дата 16.6.2008, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
****


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

Репутация: -2
Всего: 32



почитал комментарий в другую тему. 
впечатлился.
PM   Вверх
ArNic
Дата 16.6.2008, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Вот вычитал отсюда

Goto нет в php, а иногда так хочется.

“Не используйте оператор goto” – так твердили нам преподаватели в академии, и действительно оператор сей превращает код в полнейшую кашу. Поэтому разработчики php решили проблему кардинально – в php его просто нет. Но иногда очень хочется, чтобы он все таки был особенно когда пишешь обработчик какой-то формы где пользователь должен ввести сложный набор данных, а мы должны их обработать. Процесс этот проходить, как правило, в несколько этапов: печать самой формы, проверка полученных данных, предварительны показ, ну и например сохранение. Причем некоторые этапы могут повторятся : если проверка данных не прошла удачно переходим на печать формы, или если предварительный показ не устроил пользователя он может вернутся к вводу данных. Короче говоря некоторые куски кода могут задействоваться многократно. Использовать функции в этих условиях тоже не очень удобно – много входных и выходных переменных, функция должна выполнять слишком сложные действия, вообще коряво получается и читабельность кода резко падает.
И я придумал такую вот конструкцию.

Код

<?php
do {
    switch ($action) {
        default:
        break;
        case 'PRINT_FORM':
        /*
        печатаем главную форму
        */
        break;
        case 'CHECK_FORM':
        /*
        проверяем правильность данных
        */
        break;
        case 'PREVIEW_FORM':
        /*
        предворительный просмотр
        */
        break;
        case 'SAVE_FORM':
        /*
        сохраняем данные
        */
        break;
    }
} while (true);
?>



Здесь основной оператор множественного выбора switch заключен в бесконечный цикл do-while – таким образом мы группируем нужные действия в секциях case : break; и можем неограниченно переходить из одной секции к другой. В секции default: удобно сделать предварительный разбор данных например если входных данных нет то $action = ‘PRINT_FORM’ печатаем форму, если есть например $_POST [‘submit’] то тогда отправляем на обработку полученных данных $action = ‘CHECK_FORM’ . Передача управления между блоками switch происходит с помощью изменения переменной $action, ну а выход из цикла с помощью break 2; или exit;
Так например в блоке печати основной формы можно смело поставить break 2; т.к вывод формы предполагает окончание скрипта.
Конструкция очень гибкая и читабельная. Но есть один недостаток – если неправильно обработаны данные можно попасть в бесконечный цикл и скрипт зависает - это неприятно придется ждать целых 30 сек.
Давайте установим ограничение на кол-во циклов оператора do-while, 20 хватит с головой. Теперь если мы что-то накасячили скрипт намотает 20 оборотов, остановится и вывалит предупреждение об екстренном останове.
Отлаживать такую кострукцию очень удобно - достаточно после оператора swith распечатывать переменную $action и мы получим полную последовательность исполнения блоков.

Код

DO {
    //  в начале каждого цикла печатаем название
    //   выполненной секции очень удобно для отладки
    echo $action.' ';   

    SWITCH ($action) {
        default:
        break;
        case 'PRINT_FORM':
        /*
        печатаем главную форму
        */
        break;
        case 'CHECK_FORM':
        /*
        проверяем правильность данных
        */
        break;
        case 'PREVIEW_FORM':
        /*
        предворительный просмотр
        */
        break;
        case 'SAVE_FORM':
        /*
        сохраняем данные
        */
        break;
    }// end switch

} WHILE (  ( ($i++) < 20 ) or die('Принудительный останов цикла')   );


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

Добавлено через 3 минуты и 58 секунд
кстати забыл сказать как нашел: в Google по поисковой фразе goto для php

Добавлено через 7 минут и 53 секунды
Да, и не забудь прочесть историю исключения оператора goto из php
PM MAIL ICQ   Вверх
maxbrown
Дата 16.6.2008, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



ArNic, спасибо за код и ссылки, но Switch-Case не решает проблемы. К тому же, я вовсе не настаиваю на GOTO-решении, т.к. мне оно и самому не нравится. 

Утверждение: при помощи Switch мы не сможем перейти в нужную точку цикла.

Пример: обработать несколько файлов, часть из которых на момент первого запуска скрипта может ещё не существовать. Обрабатывать один и тот же файл дважды - запрещается.
Код

$fnames=LoadVariables("fnames"); // LoadVariables() возвращает сохранённую когда-то переменную, либо false, если она ранее не сохранялась
if (!$fnames) {
 $fnames=array("file1.dat", "file2.dat", "fileN.dat"); 
 SaveVariables("fnames");
} // на самом-то деле, массив читается из базы.
// и - самое важное! - через неделю база может измениться, но мы обязаны продолжать 
// обрабатывать ТОТ ЖЕ САМЫЙ массив имён файлов, который был при первом запуске
if ( ProcessFiles($fnames) == "все файлы обработаны" ) { Mail_That_All_Complete(); exit; } // Сообщаем оператору, что задача полностью выполнена
else { Shedule_Cron_For_The_Future_Launch( time()+60*60*24*7 ); exit; } // else спланируем перезапуск через неделю

function ProcessFiles($fnames, $label="") {
 for($i=0; $i<count($fnames); $i++) {
  SaveVariables("i"); // говорим функции SaveVariables, что есть переменная $i и что её необходимо сохранять перед выходом
  $label="Label1";
  SaveVariables("label"); // метку тоже нужно будет сохранить в момент выхода.

// Label1: Несуществующий оператор метки, к которому нужно вернуться через неделю,
// если СЕЙЧАС продолжить работу окажется невозможным

  if( !file_exists($fnames[$i]) ) { // Увы и ой! Этот файл ещё не создан!
   Mail_That_We_Need_This_File($fnames[$i]); // сообщим оператору на мэйл, что ждём этот файл
   return SaveVariables();
  } // if этот файл ещё не создан, продолжим его обработку через неделю. 
  else ProcessThisFile($fnames[$i]);
 } // for все имена файлов
 return "все файлы обработаны";
} // function ProcessFiles


Плохое решение:
function ProcessFiles($fnames, $i0=0) {
 for($i=$i0; $i<count($fnames); $i++) {

Недостаток решения: ну Вы же понимаете, что на самом деле там не только for и не только $i. Там ещё впереди и вокруг тьма ветвлений, циклов etc.
PM MAIL WWW ICQ   Вверх
sTa1kEr
Дата 16.6.2008, 14:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


9/10 программиста
***


Профиль
Группа: Завсегдатай
Сообщений: 1553
Регистрация: 21.2.2007

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



ArNic, Exceptions вам в помощь и не понадобятся никакие бесконечные циклы.
PM MAIL   Вверх
Feldmarschall
Дата 16.6.2008, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок
****


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

Репутация: -2
Всего: 32



maxbrown, мне неудобно столь маститому программисту указывать на детские ошибки, но проблема в данном случае происходит оттого, что путаются программа и данные. К программе применяется подход, как будто это данные.
А решение заключается в том, что исполнение программы должно контролироваться входящими данными, а не программными ухищрениями.
PM   Вверх
maxbrown
Дата 16.6.2008, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



Feldmarschall, не такой уж я "маститый программист": как и у любого самоучки, у меня есть изрядные пробелы в знаниях. В частности, копнуть глубже Exceptions (sTa1kEr, спасибо за идею!) мне почему-то не пришло в голову.
Что же касается "путания программы с данными", то к сожалению, в данном случае программа вообще является данными smile  по своему происхождению (PHP-скрипт генерится из псевдоязыка на XML, который я сейчас пишу для своих целей). Кстати, о невозможности создания языков программирования на синтаксисе XML я уже читал и пока что мне это не очень мешает  smile
Но трабла в том, что пример с обработкой пока не существующих файлов - это всего лишь пример, а сама задача заключается именно в генерации заранее (sic!) неизвестных PHP-скриптов, которые обладали бы свойством прерывать по команде свою работу, а по другой команде - возобновлять её, как будто бы ничего не произошло.
Если у Вас есть хорошая общая идея, как это можно реализовать, был бы за неё очень признателен.
PM MAIL WWW ICQ   Вверх
krundetz
Дата 16.6.2008, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вечный странник
***


Профиль
Группа: Завсегдатай
Сообщений: 1400
Регистрация: 14.6.2007
Где: НН(Сормово)

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



Цитата(maxbrown @ 16.6.2008,  10:35)
Задача: при наступлении некоего if($condition) корректно прервать работу некоего PHP-скрипта, а при следующем запуске (возможно, через несколько недель) возобновить с той же точки.

А причем здесь GOTO? У вас нет похоже четкого понимания зачем вообще эта конструкция применяется в других языках. Описываемая вами задача решается следующим способом: Создается точка остонова которая хранится на сервере допустим в базе данных. Это точка остонова является срезом системы в момент её остановки. При следующем запуске делаем проверку и если точка остонова имеется инициализируем ей состояние ситемы и начинаем работать.


--------------------
!цензоры - Хранитель стратегической жидкости
Группа ТГВ
Группа Нижний Новгород
user posted image
PM MAIL   Вверх
maxbrown
Дата 16.6.2008, 14:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



krundetz, GOTO ни при чём. Мне самому не нравится GOTO. Это лишь первый пришедший в голову, далеко не лучший и заведомо не существующий вариант решения  smile
А вот насчёт "Создается точка остонова ... точка остонова является срезом системы в момент её остановки... При следующем запуске инициализируем ей состояние ситемы и начинаем работать." - вот насчёт этого охотно почитал бы подробнее.
Только надо поиметь в виду, что таких приостановленных задач в каждый момент времени может быть несколько, плюс ещё несколько работающих (не приостановленных), и заводить ради каждой из них виртуальный сервер будет неимоверно жирно.

Это сообщение отредактировал(а) maxbrown - 16.6.2008, 15:04
PM MAIL WWW ICQ   Вверх
krundetz
Дата 16.6.2008, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вечный странник
***


Профиль
Группа: Завсегдатай
Сообщений: 1400
Регистрация: 14.6.2007
Где: НН(Сормово)

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



maxbrown я не говорил про виртуальный сервер, я говорил про хранение точек отсанова в БД.
Почитайте про паттерн Состояние, в вашей задаче это наиболее приближеное решение из известных мне. 
Насчет виртуального сервера. Если у вас продолжительность работы скрипта больше чем 30 секунд, точнее есть долгоиграющие скрипты скорее всего без этого не обойтись. Либо придется договариваться с хостерами в индивидуальном порядке.


--------------------
!цензоры - Хранитель стратегической жидкости
Группа ТГВ
Группа Нижний Новгород
user posted image
PM MAIL   Вверх
IZ@TOP
Дата 16.6.2008, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Панда-бир!
****


Профиль
Группа: Участник
Сообщений: 4795
Регистрация: 3.2.2003
Где: Бамбуковый лес

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



Цитата(maxbrown @  16.6.2008,  15:58 Найти цитируемый пост)
krundetz, GOTO ни при чём. Мне самому не нравится GOTO. Это лишь первый пришедший в голову, далеко не лучший и заведомо не существующий вариант решения 


Не так уж и несуществующий: http://www.phpconf.ru/u/_files/files/0/26.ppt


--------------------
Один из розовых плюшевых-всадников апокалипсиса... очень злой...

Семь кругов ада для новых элементов языка
Мои разрозненные мысли
PM MAIL WWW ICQ Skype GTalk   Вверх
maxbrown
Дата 16.6.2008, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



IZ@TOP, спасибо конечно, но я предпочёл бы обойтись без goto, тем более, что не факт, что мой провайдер перешёл на PHP5.3

krundetz, не подскажете ссылку точнее? А то я гуглил около часа, но нашёл только общие "языково-независимые" фразы, а конкретных примеров реализации pattern State на PHP так и не нагуглил. smile 

Это сообщение отредактировал(а) maxbrown - 16.6.2008, 17:36
PM MAIL WWW ICQ   Вверх
krundetz
Дата 16.6.2008, 18:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вечный странник
***


Профиль
Группа: Завсегдатай
Сообщений: 1400
Регистрация: 14.6.2007
Где: НН(Сормово)

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



Я тоже реализации его на PHP ни разу не видел но патnерн на то и паттерн что это некий каркас легко адаптируемый к любому языку в котором реализована OOP. Неплохим подспорьем может стать пример реализации этого паттерна на Java


--------------------
!цензоры - Хранитель стратегической жидкости
Группа ТГВ
Группа Нижний Новгород
user posted image
PM MAIL   Вверх
yurik_l
Дата 16.6.2008, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


тарантиноман



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

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



maxbrown, паттерн Состояние:
http://www.fluffycat.com/PHP-Design-Patterns/State/


PM MAIL   Вверх
maxbrown
Дата 16.6.2008, 19:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Awaiting Authorisation
Сообщений: 26
Регистрация: 16.6.2008
Где: Obninsk sci-city

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



О! yurik_l, спасибо за пример.
Теперь сразу всё стало понятно... И, к сожалению, стало также понятно, что этот паттерн в моём случае малопригоден:

1. Слишком уж в моём случае большое (а главное - заранее не известное!) количество состояний. Плюс внутри мы наблюдаем нечто ещё худшее, нежели Switch-Case: по сути, для каждого состояния описывается свой собственный метод, пусть и динамически присваеваемый! А у меня-то вместо State-зависимых методов - State-зависимые операторы! И получится в итоге вместо if($a==$b) { ... } конструкция вида if( this->GetSkipCondition("\$a==\$b") ) { ... }, а во что превратятся циклы foreach, я даже представить себе боюсь.

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

3. Блин, ну неужели нельзя придумать более простого способа? Задача-то была всего-навсего приостановить выполнение скрипта на какое-то длительное время...
PM MAIL WWW ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса

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

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


 




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


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

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