Slim 3, какой обработчик ошибок будет записывать данные о бесконечном цикле [duplicate]

Вот пример использования контроллера, введенного Guice.

/**
 * Loads a FXML file and injects its controller from the given Guice {@code Provider}
 */
public abstract class GuiceFxmlLoader {

   public GuiceFxmlLoader(Stage stage, Provider<?> provider) {
      mStage = Objects.requireNonNull(stage);
      mProvider = Objects.requireNonNull(provider);
   }

   /**
    * @return the FXML file name
    */
   public abstract String getFileName();

   /**
    * Load FXML, set its controller with given {@code Provider}, and add it to {@code Stage}.
    */
   public void loadView() {
      try {
         FXMLLoader loader = new FXMLLoader(getClass().getClassLoader().getResource(getFileName()));
         loader.setControllerFactory(p -> mProvider.get());
         Node view = loader.load();
         setViewInStage(view);
      }
      catch (IOException ex) {
         LOGGER.error("Failed to load FXML: " + getFileName(), ex);
      }
   }

   private void setViewInStage(Node view) {
      BorderPane pane = (BorderPane)mStage.getScene().getRoot();
      pane.setCenter(view);
   }

   private static final Logger LOGGER = Logger.getLogger(GuiceFxmlLoader.class);

   private final Stage mStage;
   private final Provider<?> mProvider;
}

Вот конкретная реализация загрузчика:

public class ConcreteViewLoader extends GuiceFxmlLoader {

   @Inject
   public ConcreteViewLoader(Stage stage, Provider<MyController> provider) {
      super(stage, provider);
   }

   @Override
   public String getFileName() {
      return "my_view.fxml";
   }
}

Обратите внимание, что этот пример загружает представление в центр BoarderPane, который является корнем сцены в рабочей области. Это не относится к примеру (деталь реализации моего конкретного варианта использования), но решил оставить его, поскольку некоторые из них могут оказаться полезными.

51
задан ingh.am 28 July 2011 в 15:53
поделиться

8 ответов

Ваши единственные варианты - увеличить допустимое время выполнения (установка его на 0 делает его бесконечным, но это не рекомендуется) скрипта или порождает новый поток и надеется на лучшее.

причина в том, что это не увлекательно, так это то, что его не бросают. Ни одна строка кода не вызвала ошибку, скорее, PHP сказал: «Нет, простите, это слишком долго. Пора прекратить сейчас». И это имеет смысл. Представьте, что у вас есть сценарий с максимальным временем выполнения 30 секунд, который поймает эту ошибку и займет еще 30 секунд ... в плохо разработанной программе, которая открывает некоторые довольно неприятные возможности для использования. Как минимум, это создаст возможности для DOS атак.

24
ответ дан cwallenpoole 18 August 2018 в 00:04
поделиться
  • 1
    Как установить время исключения на 0 и затем выполнить мой собственный тайм-аут? – ingh.am 28 July 2011 в 16:02
  • 2
    Это может работать в некоторых случаях, но не для всех. Было бы лучше, если бы это было в какой-то форме цикла, чтобы вы могли регулярно тестировать. – cwallenpoole 28 July 2011 в 16:11
  • 3
    Хм. Причина, по которой я это заметил, заключалась в получении пакетов пакетов. Я установил размер пакета как что-то очень маленькое, и навсегда потребовалось отправить. Мое мышление заключается в том, что если бы было отправлено много данных с размером пакета примерно на 1024 байта, я мог бы установить свой собственный тайм-аут в этом цикле и отреагировать в течение нескольких секунд, чтобы предупредить пользователя. – ingh.am 28 July 2011 в 16:31
  • 4
    Я возражаю против того, чтобы PHP был помечен PHP в отношении того, допускает ли ошибка кодирования бесконечные циклы или эксплойты DOS и т. Д. Я думаю, что для обработки ошибки должно быть до программиста. Возможно, тайм-аут происходит во время cURL, и я хочу, чтобы страница обновлялась бесконечно до тех пор, пока она не заново соединится с URL-адресом (потому что линия T1 выключена или, возможно, удаленный сервер, кто знает?). Мне не нужен мой предварительный процессор, будь то php, asp, cgi и т. Д., Чтобы принять это решение для меня. Я не думаю, что предварительный процессор или даже язык на стороне клиента, такой как javascript, должны принимать этические или моральные решения от моего имени. – TARKUS 16 June 2016 в 19:41
  • 5
    Существуют и другие варианты, которые вы можете использовать, связанные с таймаутами, но это не распространяется на этот вопрос. Наиболее распространенная практика заключается в том, чтобы просто убедиться, что запрос не занимает более 60 секунд. В этот момент вы все равно не будете публичными. – cwallenpoole 16 June 2016 в 20:39

Как пробовать в качестве документации PHP (ну ... хотя бы один из ее читателей) сказать:

<?php 
function shutdown() 
 { 
     $a=error_get_last(); 
     if($a==null)   
         echo "No errors"; 
     else 
          print_r($a); 

 } 
register_shutdown_function('shutdown'); 
ini_set('max_execution_time',1 ); 
sleep(3); 
?>

Посмотрите на следующие ссылки:

  1. http://www.php.net/manual/en/function.set-error-handler.php#106061
  2. http: //www.php .net / manual / en / function.register-shutdown-function.php
64
ответ дан Adi Lester 18 August 2018 в 00:04
поделиться
  • 1
    Это, возможно, лучший секрет php, который я никогда не видел. Потрясающие. – Anthony 16 March 2013 в 17:28
  • 2
    Я протестировал его. Но пока отображается фатальное сообщение об ошибке. Можно ли избежать этого. В любом случае я использовал ini_set ('display_errors', '0'); – B L Praveen 13 August 2014 в 07:16
  • 3
    sleep () фактически не влияет на счетчик времени, что является странным, но верно. Таким образом, вы должны сделать что-то еще, чтобы проверить свою функцию shutdown () - пара вложенных циклов, каждая из которых повторяется миллион раз, должна это сделать. – Bobby Jack 10 December 2014 в 15:02
  • 4
    @BobbyJack Хотя это странно, это имеет смысл, так как спящий поток прекращает выполнение в течение определенного периода времени. Поскольку его выполнение не выполняется, это время не считается истекшим временем выполнения. – Joseph Pla 5 May 2015 в 21:46

Это не исключение, это ошибка. Существуют важные различия между исключениями и ошибками, прежде всего ошибки не могут быть захвачены семантикой try / catch.

PHP-скрипты построены вокруг парадигмы короткого времени выполнения, поэтому по умолчанию PHP настроен на то, чтобы предположить, что если скрипт работает более 30 секунд, он должен быть пойман в бесконечном цикле и, следовательно, должен быть прекращено. Это делается для предотвращения ошибочного PHP-скрипта, вызывающего отказ в обслуживании, либо случайно, либо злонамеренным намерением.

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

Вы можете попробовать изменить максимальное время выполнения, используя set_time_limit() или изменив значение max_execution_time в php.ini файл для повышения лимита. вы также можете полностью удалить предел, установив время выполнения равным 0, хотя это не рекомендуется.

set_time_limit() может быть отключен такими механизмами, как disable_functions , поэтому он может быть недоступен для вас, также у вас может не быть доступа к php.ini. Если это так, тогда вам следует обратиться за помощью к своему хозяину.

Исключением являются PHP-скрипты, запущенные из командной строки. В этих условиях работы скрипты PHP могут быть интерактивными и нуждаются в длительной обработке данных или ожидании ввода. По этой причине по умолчанию для скриптов, запущенных из командной строки, не существует предела max_execution_time.


РЕДАКТИРОВАТЬ ДОБАВИТЬ: обработка ошибок PHP 7 прошла капитальный ремонт. Я считаю, что ошибки и исключения теперь являются подклассами Throwable. Это может сделать вышеизложенное больше не актуальным для PHP7 +, хотя мне придется более внимательно изучить особенности обработки ошибок теперь.

17
ответ дан GordonM 18 August 2018 в 00:04
поделиться

Да, я протестировал решение TheJanOnline. sleep () не учитывает время выполнения php, поэтому здесь находится версия WORKING с неопределенным циклом:

<?php 
function shutdown() 
 { 
     $a=error_get_last(); 
     if($a==null)   
         echo "No errors"; 
     else 
          print_r($a); 

 } 
register_shutdown_function('shutdown'); 
ini_set('max_execution_time',1 ); 
while(1) {/*nothing*/}
// will die after 1 sec and print error
?>

3
ответ дан Michal 18 August 2018 в 00:04
поделиться

Вы ничего не можете с этим поделать. но вы можете иметь изящное выключение, используя register_shutdown_function

<?php 

ini_set('display_errors', '0');         
ini_set("max_execution_time",15 ); //you can use this if you know your script should not take longer than 15 seconds to finish

register_shutdown_function('shutdown');


function shutdown() 
{ 
       $error = error_get_last();

       if ($error['type'] === E_ERROR) {

      //do your shutdown stuff here
      //be care full do not call any other function from within shutdown function
      //as php may not wait until that function finishes
      //its a strange behavior. During testing I realized that if function is called 
      //from here that function may or may not finish and code below that function
      //call may or may not get executed. every time I had a different result. 

      // e.g.

      other_function();

      //code below this function may not get executed

       } 

} 

while(true)
{

}

function other_function()
{
  //code in this function may not get executed if this function
  //called from shutdown function
} 

?>
6
ответ дан pinkal vansia 18 August 2018 в 00:04
поделиться
  • 1
    будет ли other_function() вызываться во время выключения, если он был объявлен перед бесконечным циклом? – Douglas.Sesar 28 July 2014 в 14:47
  • 2
    @ Douglas.Sesar other_function () будет вызван любым способом. Но нет гарантии, что он завершится, и любой код ниже вызовет функцию. Если other_function () занимает очень мало времени, чтобы сделать что-то очень мало, это может закончиться, и любой код ниже вызовет функцию. Но если для выполнения задачи требуется слишком много времени, то нет гарантии, что она полностью закончится! – pinkal vansia 15 October 2014 в 12:32
  • 3
    В самом строгом смысле вопрос OP, это решение работает. Я хочу признать, что весна высаживается на мой отработанный ответ от вашего ответа. – TARKUS 16 June 2016 в 20:00

поместите это в начало файла php

<?php
    set_time_limit(0);

EDIT 1

, но сначала проверьте, нет ли такого кода:

while (1=1) {
  echo '=)';
}

EDIT 2

, чтобы поймать эту ошибку. set_error_handler

-3
ответ дан Subdigger 18 August 2018 в 00:04
поделиться

Я придумал это на основе ответа @ pinkal-vansia. Поэтому я не претендую на оригинальный ответ, но ответ с практическим приложением. Мне нужен был способ обновить страницу в случае таймаута. Поскольку я наблюдал достаточное количество тайм-аутов моего скрипта cURL, чтобы знать, что код работает, но иногда по какой-либо причине он не может подключиться к удаленному серверу или полностью прочитать обслуживаемый html, и что при обновлении проблема исчезнет, ​​я все в порядке, когда скрипт обновляется, чтобы «вылечить» максимальную ошибку таймаута выполнения.

<?php //script name: scrape_script.php

ini_set('max_execution_time', 300);

register_shutdown_function('shutdown');

function shutdown() 
{ 
    ?><meta http-equiv="refresh" content="0; url=scrape_script.php"><?php
    // just do a meta refresh. Haven't tested with header location, but
    // this works fine.
}

FYI, 300 секунд не слишком длинный для скрипта скремблирования, который я запускаю, что занимает чуть меньше что для извлечения данных из типов страниц я соскабливаю. Иногда это происходит через несколько секунд только из-за неравномерности соединения. Зная, что это время соединения, которое иногда терпит неудачу, а не обработку скриптов, лучше не увеличивать таймаут, а просто просто обновлять страницу и повторять попытку.

4
ответ дан TARKUS 18 August 2018 в 00:04
поделиться

В некоторых случаях есть небольшой сложный способ обработки «Неустранимая ошибка: максимальное время выполнения 30 секунд» в качестве исключения:

function time_sublimit($k = 0.8) {
    $limit = ini_get('max_execution_time'); // changes even when you set_time_limit()
    $sub_limit = round($limit * $k);
    if($sub_limit === 0) {
        $sub_limit = INF;
    }
    return $sub_limit;
}

В коде вы должны измерить время выполнения и бросить исключение может быть вызвано фатальной ошибкой таймаута. $ k = 0.8 - это 80% от допустимого времени выполнения, поэтому у вас есть 20% времени для обработки исключения.

try{
    $t1 = time(); // start to mesure time.
    while (true) { // put your long-time loop condition here
        time_spent = time() - $t1;
        if(time_spent >= time_sublimit()) {
            throw new Exception('Time sublimit reached');
        }
        // do work here
    }
} catch(Exception $e) {
    // catch exception here
}
4
ответ дан user3901681 18 August 2018 в 00:04
поделиться
  • 1
    Это будет работать, если у вас есть работа, которая хорошо сегментирована, чтобы ее можно было повторить, но если одна большая операция или последовательность операций висит вокруг до истечения срока, вы по-прежнему в значительной степени являетесь SOL. – Josip Rodin 15 September 2015 в 14:06
Другие вопросы по тегам:

Похожие вопросы: