捕获 token_get_all (Tokenizer) 抛出的错误

Posted

技术标签:

【中文标题】捕获 token_get_all (Tokenizer) 抛出的错误【英文标题】:Catching errors thrown by token_get_all (Tokenizer) 【发布时间】:2011-09-07 21:52:49 【问题描述】:

phptoken_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 开始就没有)。

【讨论】:

遗憾的是,这不起作用(正如我在问题中已经提到的那样):token_get_all 抛出 E_COMPILE_WARNING 这是错误处理程序无法捕获的错误类型之一:( 看这个php.net/manual/en/errorfunc.constants.php我会得出结论,你可以赶上E_COMPILE_WARNING,你确定你设置了正确的error_reporting级别吗? 不幸的是,set_error_handler()'s documentation(尽管与提出这个问题时的 PHP 版本完全不同),用户定义的错误处理程序无法处理 E_ERRORE_PARSEE_CORE_ERROR、@ 987654338@、E_COMPILE_ERRORE_COMPILE_WARNING,或大部分E_STRICT

以上是关于捕获 token_get_all (Tokenizer) 抛出的错误的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 刀片模板不起作用 - 调用未定义的函数 Illuminate\View\Compilers\token_get_all()

基于其后缀删除整个PHP函数

php代码奇巧淫技

scrapy安装遇到的Twisted问题

django序列化数据提取名词

Boost::tokenizer 逗号分隔 (c++)