За последние 24 часа нас посетили 22583 программиста и 1106 роботов. Сейчас ищет 581 программист ...

Почему set_exception_handler() не перехватывает исключения Fatal error?

Тема в разделе "PHP для профи", создана пользователем qtk, 1 дек 2019.

  1. qtk

    qtk Активный пользователь

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Вроде бы простой код:
    PHP:
    1. set_exception_handler(function (Throwable $t) {
    2.     echo $t->getMessage;
    3. });
    4.  
    5. require_once 'not-exists.php';
    Вылазит ошибка, а должно быть исключение: Fatal error: main(): Failed opening required 'not-exists.php' (include_path='.;e:/ospanel/modules/php/PHP-7.1;e:/ospanel/modules/php/PHP-7.1/PEAR/pear') in
    ..............\test.php on line 10
     
  2. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    А какая ошибка то вылазит?
     
  3. qtk

    qtk Активный пользователь

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Fatal error: main(): Failed opening required 'not-exists.php' (include_path='.;e:/ospanel/modules/php/PHP-7.1;e:/ospanel/modules/php/PHP-7.1/PEAR/pear') in
    ..............\test.php on line 10

    Но я ждал исключение. Возможно я чего-то недопонимаю https://www.php.net/manual/ru/language.errors.php7.php
     
  4. Sail

    Sail Старожил

    С нами с:
    1 ноя 2016
    Сообщения:
    1.591
    Симпатии:
    360
    @qtk, однако, загвоздка в использовании анонимной функции.
     
  5. qtk

    qtk Активный пользователь

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    однако, нет)
     
  6. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    #6 artoodetoo, 2 дек 2019
    Последнее редактирование: 2 дек 2019
  7. qtk

    qtk Активный пользователь

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Спасибо, буду читать
     
  8. qdevelopment

    qdevelopment Новичок

    С нами с:
    13 окт 2019
    Сообщения:
    41
    Симпатии:
    13
    Там нечего перехватывать.

    Задает обработчик по умолчанию для случаев, когда исключение выброшено вне блока try/catch. После вызова exception_handler выполнение будет остановлено.
    https://www.php.net/manual/ru/function.set-exception-handler.php
     
    #8 qdevelopment, 2 дек 2019
    Последнее редактирование: 2 дек 2019
  9. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    @qdevelopment нечего в смысле ты не перехватишь через try-catch подобную ошибку:
    Fatal error: main(): Failed opening required 'not-exists.php'

    :)

    предлагаю попробовать.
    --- Добавлено ---
    PHP:
    1. <?php
    2.  
    3. function exception_handler(\Throwable $exception) {
    4.   echo "Error intercepted!\n";
    5. }
    6. set_exception_handler('exception_handler');
    7.  
    8. try {
    9.   require 'nonexistent.php';
    10. } catch (\Throwable $e) {
    11.   echo "Got it!\n";
    12. }
    не будет сообщения "Got it!" или "Error intercepted!"
    некоторые ошибки более шустрые чем другие.
     
    #9 artoodetoo, 2 дек 2019
    Последнее редактирование: 2 дек 2019
  10. qdevelopment

    qdevelopment Новичок

    С нами с:
    13 окт 2019
    Сообщения:
    41
    Симпатии:
    13
    @artoodetoo чтобы set_exception_handler подхватил исключение, сперва это исключение должно быть выброшено. То что файла not-exists.php нет, не выбрасывает исключение, а получает fatal error. Т.е ему надо с помощью set_error_handler сперва подхватить ошибку и там выбросить throw new Exception, чтобы заработал set_exception_handler

    Или же писать что-то типа
    PHP:
    1. set_exception_handler(function (Throwable $t) {
    2.     echo $t->getMessage();
    3. });
    4.  
    5. if (!file_exists('not-exists.php')) {
    6.     throw new Exception('No such file');
    7. }
     
    #10 qdevelopment, 2 дек 2019
    Последнее редактирование: 2 дек 2019
    artoodetoo нравится это.
  11. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    @qdevelopment спасибо, хорошее замечание про error handler. Исторически сложилось, что в PHP есть старый вид ошибок и исключения. Они как бы параллельно существуют. Хотя в свежих версиях языка их пытаются привести к общему знаменателю через интерфейс Throwable.

    Конечно, в данном случае можно соломки постелить и проверять наличие файла через if. Или заменить require на include и так добиться снижения уровня ошибки до Warning. Ибо Fatal error неизбежно прерывает выполнение скрипта, даже с set_error_handler().
     
    qdevelopment нравится это.
  12. qdevelopment

    qdevelopment Новичок

    С нами с:
    13 окт 2019
    Сообщения:
    41
    Симпатии:
    13
    @artoodetoo Да точно, совсем забыл, что в require ошибка уровня E_COMPILE_ERROR, поэтому set_error_handler не поможет. Идея с заменой require на include, думаю самая оптимальная.
     
  13. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.072
    Симпатии:
    1.237
    Адрес:
    там-сям
    сделал тестовый полигон. не знаю насколько он будет понятен топикстартеру, но вот:
    описаны 4 случая разных ошибок, можно раскомментировать одну из них и закомментировать остальные и смотреть что выведется в итоге.

    PHP:
    1. <?php
    2.  
    3.  
    4. function legacy_error_handler($errno, $errstr, $errfile, $errline)
    5. {
    6. #  if (0 === error_reporting()) {
    7. #  return false;
    8. #  }
    9.  echo "Error intercepted\n";
    10.   throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
    11. }
    12. set_error_handler('legacy_error_handler');
    13.  
    14. function exception_handler(\Throwable $exception) {
    15.   echo "Exception intercepted without try-catch!\n";
    16. }
    17. set_exception_handler('exception_handler');
    18.  
    19. try {
    20.  
    21.   // 1. "natural" fatal error  
    22.   require 'nonexistent.php';
    23.  
    24.   // 2. warning
    25. #  1/0;
    26.  
    27.   // 3. user generated error/warning
    28. #  trigger_error('OOPS!', E_USER_WARNING);
    29.  
    30.   // 4. raise exception
    31. #  throw new \Exception('OMG OMG OMG');
    32.  
    33. } catch (\Throwable $e) { // For PHP 7
    34.   echo "Cought as Throwable\n";
    35.  
    36. } catch (\Exception $e) { // For PHP 5
    37.   // handle $e
    38.   echo "Cought as Exception\n";
    39. }
    40.  
    41. echo "Continue\n";
    --- Добавлено ---
    Если увидел строку "Continue", значит ошибка полностью под контролем.
     
    Valick нравится это.
  14. Valick

    Valick Активный пользователь

    С нами с:
    12 авг 2018
    Сообщения:
    1.911
    Симпатии:
    328
    Главное не сходить с ума, не впадать в крайности и исключения использовать для исключительных ситуаций. А наличие, чтение и запись файла надо проверять и обрабатывать соответствующим образом.
     
  15. qtk

    qtk Активный пользователь

    С нами с:
    18 дек 2013
    Сообщения:
    29
    Симпатии:
    0
    Всем огромное спасибо за помощь!!!!