捕获token_get_all(Tokenizer)引发的错误

Nik*_*kiC 5 php error-handling tokenize

PHP token_get_all函数(允许将PHP源代码转换为标记)可能会抛出两个错误:一个是遇到未终止的多行注释,另一个是遇到意外的char.

我想抓住这些错误并将其作为例外.

问题是:由于这些错误是解析错误,因此无法使用您通常使用的错误处理函数来处理它们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]);
}
Run Code Online (Sandbox Code Playgroud)

很明显,我对使用该解决方案并不感到兴奋.特别是我error_get_last通过访问未定义的变量重置错误消息的事实似乎非常不令人满意.

那么:这个问题有更好的解决方案吗?

Hal*_*yon -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();
Run Code Online (Sandbox Code Playgroud)

通常验证和执行是两个独立的事情,但似乎没有办法验证/lint 一段 PHP 代码(至少从 5.x 开始就没有)。