Перехват ошибок, выдаваемых token_get_all (Tokenizer)

#php #error-handling #tokenize

#php #обработка ошибок #маркировать

Вопрос:

Функция PHPs token_get_all (которая позволяет преобразовывать исходный код PHP в токены) может выдавать две ошибки: одну, если встречается многострочный комментарий без обработки, другую, если обнаружен неожиданный символ.

Я хотел бы перехватить эти ошибки и выдать их как исключения.

Проблема в том, что, поскольку эти ошибки являются ошибками синтаксического анализа, они не могут быть обработаны с помощью функции обработки ошибок, которую вы обычно указываете с помощью set_error_handler .

В настоящее время я реализовал следующее:

 // Reset the error message in error_get_last()
@$errorGetLastResetUndefinedVariable;

$this->tokens = @token_get_all($code);

$error = error_get_last();

if (preg_match(
        '~^(Unterminated comment) starting line ([0-9] )$~',
        $error['message'],
        $matches
    )
) {
    throw new ParseErrorException($matches[1], $matches[2]);
}

if (preg_match(
        '~^(Unexpected character in input:s '(.)' (ASCII=[0-9] ))~s',
        $error['message'],
        $matches
    )
) {
    throw new ParseErrorException($matches[1]);
}
  

Должно быть очевидно, что я не очень рад использовать это решение. Особенно тот факт, что я сбрасываю сообщение об ошибке в error_get_last при доступе к неопределенной переменной, кажется довольно неудовлетворительным.

Итак: есть ли лучшее решение этой проблемы?

Ответ №1:

Установите пользовательский обработчик ошибок с помощью set_error_handler . Вызов token_get_all . Затем отключите обработчик ошибок, вызвав restore_error_handler .

Это позволит вам перехватывать предупреждения. Убедитесь, что вы удалили @ подавитель. Вы можете, например, зарегистрировать обработчик ошибок, который находится в классе, который будет просто записывать любые предупреждения для последующей проверки.

Непроверенный пример кода:

 class CatchWarnings {

    private $warnings = array();

    public function handler($errno, $errstr, $errfile, $errline) {
        switch ($errno) {
        case E_USER_WARNING:
            $this->warnings[] = $errstr;
            return true;    // cancel error handling bubble
        }
        return false;   // error handling as usual
    }

    public function has_warnings() {
        return count($this->warnings) > 0;
    }
}

$cw = new CatchWarnings();
set_error_handler(array($cw, "handler"));
token_get_all();
restore_error_handler();
  

Обычно проверка и выполнение — это две разные вещи, но, похоже, нет способа проверить / удалить фрагмент PHP-кода (во всяком случае, с 5.x).

Комментарии:

1. К сожалению, это не работает (как я уже упоминал в вопросе): token_get_all выдает E_COMPILE_WARNING , и это один из типов ошибок, которые не могут быть перехвачены обработчиком ошибок : (

2. Глядя на это php.net/manual/en/errorfunc.constants.php Я бы сделал вывод, что вы можете перехватывать E_COMPILE_WARNING , вы уверены, что установили правильный error_reporting уровень?

3. К сожалению, согласно set_error_handler() документации E_ERROR (хотя и относящейся к совершенно другой версии PHP, чем когда был задан этот вопрос), определяемые пользователем обработчики ошибок не могут обрабатывать E_PARSE , E_CORE_ERROR E_CORE_WARNING , E_COMPILE_ERROR E_COMPILE_WARNING E_STRICT , ,, или большую часть из,,,,,,,,,,,,,,,,,,,.