![]() |
Модераторы: skyboy, MoLeX, Aliance, ksnk |
![]() ![]() ![]() |
|
maxbrown |
|
|||
![]() Новичок Профиль Группа: 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 |
|||
|
||||
Feldmarschall |
|
|||
Новичок ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2641 Регистрация: 11.12.2007 Репутация: -2 Всего: 32 |
почитал комментарий в другую тему.
впечатлился. |
|||
|
||||
ArNic |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 278 Регистрация: 3.1.2007 Репутация: нет Всего: нет |
Вот вычитал отсюда
Goto нет в php, а иногда так хочется. “Не используйте оператор goto” – так твердили нам преподаватели в академии, и действительно оператор сей превращает код в полнейшую кашу. Поэтому разработчики php решили проблему кардинально – в php его просто нет. Но иногда очень хочется, чтобы он все таки был особенно когда пишешь обработчик какой-то формы где пользователь должен ввести сложный набор данных, а мы должны их обработать. Процесс этот проходить, как правило, в несколько этапов: печать самой формы, проверка полученных данных, предварительны показ, ну и например сохранение. Причем некоторые этапы могут повторятся : если проверка данных не прошла удачно переходим на печать формы, или если предварительный показ не устроил пользователя он может вернутся к вводу данных. Короче говоря некоторые куски кода могут задействоваться многократно. Использовать функции в этих условиях тоже не очень удобно – много входных и выходных переменных, функция должна выполнять слишком сложные действия, вообще коряво получается и читабельность кода резко падает. И я придумал такую вот конструкцию.
Здесь основной оператор множественного выбора 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 и мы получим полную последовательность исполнения блоков.
Реальный обработчик формы конечно может быть намного сложней и обрабатывать данные в несколько форм-этапов. Хотя конечно можно все размазать по разным скриптам, и использовать функции для группировки кода тут уже дело вкуса. Добавлено через 3 минуты и 58 секунд кстати забыл сказать как нашел: в Google по поисковой фразе goto для php Добавлено через 7 минут и 53 секунды Да, и не забудь прочесть историю исключения оператора goto из php |
||||
|
|||||
maxbrown |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 26 Регистрация: 16.6.2008 Где: Obninsk sci-city Репутация: нет Всего: нет |
ArNic, спасибо за код и ссылки, но Switch-Case не решает проблемы. К тому же, я вовсе не настаиваю на GOTO-решении, т.к. мне оно и самому не нравится.
Утверждение: при помощи Switch мы не сможем перейти в нужную точку цикла. Пример: обработать несколько файлов, часть из которых на момент первого запуска скрипта может ещё не существовать. Обрабатывать один и тот же файл дважды - запрещается.
Плохое решение: function ProcessFiles($fnames, $i0=0) { for($i=$i0; $i<count($fnames); $i++) { Недостаток решения: ну Вы же понимаете, что на самом деле там не только for и не только $i. Там ещё впереди и вокруг тьма ветвлений, циклов etc. |
|||
|
||||
sTa1kEr |
|
|||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 11 Всего: 146 |
ArNic, Exceptions вам в помощь и не понадобятся никакие бесконечные циклы.
|
|||
|
||||
Feldmarschall |
|
|||
Новичок ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2641 Регистрация: 11.12.2007 Репутация: -2 Всего: 32 |
maxbrown, мне неудобно столь маститому программисту указывать на детские ошибки, но проблема в данном случае происходит оттого, что путаются программа и данные. К программе применяется подход, как будто это данные.
А решение заключается в том, что исполнение программы должно контролироваться входящими данными, а не программными ухищрениями. |
|||
|
||||
maxbrown |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 26 Регистрация: 16.6.2008 Где: Obninsk sci-city Репутация: нет Всего: нет |
Feldmarschall, не такой уж я "маститый программист": как и у любого самоучки, у меня есть изрядные пробелы в знаниях. В частности, копнуть глубже Exceptions (sTa1kEr, спасибо за идею!) мне почему-то не пришло в голову.
Что же касается "путания программы с данными", то к сожалению, в данном случае программа вообще является данными ![]() ![]() Но трабла в том, что пример с обработкой пока не существующих файлов - это всего лишь пример, а сама задача заключается именно в генерации заранее (sic!) неизвестных PHP-скриптов, которые обладали бы свойством прерывать по команде свою работу, а по другой команде - возобновлять её, как будто бы ничего не произошло. Если у Вас есть хорошая общая идея, как это можно реализовать, был бы за неё очень признателен. |
|||
|
||||
krundetz |
|
|||
![]() Вечный странник ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1400 Регистрация: 14.6.2007 Где: НН(Сормово) Репутация: 1 Всего: 69 |
А причем здесь GOTO? У вас нет похоже четкого понимания зачем вообще эта конструкция применяется в других языках. Описываемая вами задача решается следующим способом: Создается точка остонова которая хранится на сервере допустим в базе данных. Это точка остонова является срезом системы в момент её остановки. При следующем запуске делаем проверку и если точка остонова имеется инициализируем ей состояние ситемы и начинаем работать. |
|||
|
||||
maxbrown |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 26 Регистрация: 16.6.2008 Где: Obninsk sci-city Репутация: нет Всего: нет |
krundetz, GOTO ни при чём. Мне самому не нравится GOTO. Это лишь первый пришедший в голову, далеко не лучший и заведомо не существующий вариант решения
![]() А вот насчёт "Создается точка остонова ... точка остонова является срезом системы в момент её остановки... При следующем запуске инициализируем ей состояние ситемы и начинаем работать." - вот насчёт этого охотно почитал бы подробнее. Только надо поиметь в виду, что таких приостановленных задач в каждый момент времени может быть несколько, плюс ещё несколько работающих (не приостановленных), и заводить ради каждой из них виртуальный сервер будет неимоверно жирно. Это сообщение отредактировал(а) maxbrown - 16.6.2008, 15:04 |
|||
|
||||
krundetz |
|
|||
![]() Вечный странник ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1400 Регистрация: 14.6.2007 Где: НН(Сормово) Репутация: 1 Всего: 69 |
maxbrown я не говорил про виртуальный сервер, я говорил про хранение точек отсанова в БД.
Почитайте про паттерн Состояние, в вашей задаче это наиболее приближеное решение из известных мне. Насчет виртуального сервера. Если у вас продолжительность работы скрипта больше чем 30 секунд, точнее есть долгоиграющие скрипты скорее всего без этого не обойтись. Либо придется договариваться с хостерами в индивидуальном порядке. |
|||
|
||||
IZ@TOP |
|
|||
![]() Панда-бир! ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 4795 Регистрация: 3.2.2003 Где: Бамбуковый лес Репутация: 1 Всего: 73 |
Не так уж и несуществующий: http://www.phpconf.ru/u/_files/files/0/26.ppt -------------------- Один из розовых плюшевых-всадников апокалипсиса... очень злой... Семь кругов ада для новых элементов языка Мои разрозненные мысли |
|||
|
||||
maxbrown |
|
|||
![]() Новичок Профиль Группа: Awaiting Authorisation Сообщений: 26 Регистрация: 16.6.2008 Где: Obninsk sci-city Репутация: нет Всего: нет |
IZ@TOP, спасибо конечно, но я предпочёл бы обойтись без goto, тем более, что не факт, что мой провайдер перешёл на PHP5.3
krundetz, не подскажете ссылку точнее? А то я гуглил около часа, но нашёл только общие "языково-независимые" фразы, а конкретных примеров реализации pattern State на PHP так и не нагуглил. ![]() Это сообщение отредактировал(а) maxbrown - 16.6.2008, 17:36 |
|||
|
||||
krundetz |
|
|||
![]() Вечный странник ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1400 Регистрация: 14.6.2007 Где: НН(Сормово) Репутация: 1 Всего: 69 |
Я тоже реализации его на PHP ни разу не видел но патnерн на то и паттерн что это некий каркас легко адаптируемый к любому языку в котором реализована OOP. Неплохим подспорьем может стать пример реализации этого паттерна на Java
|
|||
|
||||
yurik_l |
|
|||
тарантиноман Профиль Группа: Участник Сообщений: 49 Регистрация: 17.9.2006 Репутация: 1 Всего: 3 |
||||
|
||||
maxbrown |
|
|||
![]() Новичок Профиль Группа: 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. Блин, ну неужели нельзя придумать более простого способа? Задача-то была всего-навсего приостановить выполнение скрипта на какое-то длительное время... |
|||
|
||||
![]() ![]() ![]() |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | PHP: Для профи | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |