为什么这个错误处理函数会导致domdocument()挂起?


why would does this error handling function cause domdocument() to hang?

我包含了这个简单的错误处理函数来格式化错误:

date_default_timezone_set('America/New_York');
// Create the error handler.
function my_error_handler ($e_number, $e_message, $e_file, $e_line, $e_vars) {
    // Build the error message.
    $message = "An error occurred in script '$e_file' on line $e_line: 'n<br />$e_message'n<br />";
    // Add the date and time.
    $message .= "Date/Time: " . date('n-j-Y H:i:s') . "'n<br />";
    // Append $e_vars to the $message.
    $message .= "<pre>" . print_r ($e_vars, 1) . "</pre>'n<br />";
    echo '<div id="Error">' . $message . '</div><br />';
} // End of my_error_handler() definition.
// Use my error handler.
set_error_handler ('my_error_handler');

当我在一个脚本中包含它时,下面的

$dom = new DOMDocument();
$dom->loadHTML($output);
$xpath = new DOMXPath($dom);

和解析网页(在这种情况下,http://www.ssense.com/women/designers/all/all/page_1,我有权限解析),我得到错误,如

AN ERROR OCCURRED IN SCRIPT '/HSPHERE/LOCAL/HOME/SITE.COM/SCRIPT.PHP' ON LINE 59: 
DOMDOCUMENT::LOADHTML(): HTMLPARSEENTITYREF: NO NAME IN ENTITY, LINE: 57

AN ERROR OCCURRED IN SCRIPT '/HSPHERE/LOCAL/HOME/SITE.COM/SCRIPT.PHP' ON LINE 59: 
DOMDOCUMENT::LOADHTML(): TAG NAV INVALID IN ENTITY, LINE: 58

有很多错误,页面从未完成加载。但是,如果不包含此错误处理程序,则

$dom->loadHTML($output);

不会抛出任何错误,我在几秒钟内就得到了预期的结果。我假设错误处理程序正在捕获与loadHTML()相关的警告,这些警告没有以其他方式报告。(即使我使用

)
@$dom->loadHTML($output);

它仍然报告错误。)如何修改错误处理程序以适应对loadHTML()的调用,或者以其他方式修复此问题?

您正在加载的网页包含许多错误。例如,&而不是HTML中的&amp;实体。

PHP DOM使用libxml,因此要禁用所有错误,请插入以下行:

libxml_use_internal_errors(true);

稍后可以使用libxml_get_errors()获得解析错误列表。

导致错误的不是自定义错误处理程序。

我运行了以下代码,没有自定义错误处理程序:

$output = file_get_contents("http://www.ssense.com/women/designers/all/all/page_1");
$dom = new DOMDocument();
$dom->loadHTML($output);
$xpath = new DOMXPath($dom);

当我运行它时,我得到了大量的警告消息,类似于你的错误处理程序。

我想你看到的问题只是你的错误处理程序报告了PHP默认不报告的错误。

默认情况下,错误报告的级别由您的php.ini设置决定,但可以通过使用error_reporting()函数来覆盖。当您设置自己的错误处理程序时,您必须自己确定要处理的报告级别。您的错误处理程序将在上调用每个错误和通知,因此您将为输出所有的错误消息,除非您显式检查针对当前error_reporting()级别生成的错误。

请记住,使用@错误抑制操作符只是为该行设置error_reporting(0)的简写。例如,这一行:

@$dom->loadHTML($output);

是以下内容的简写:

$errorLevel = error_reporting(0);
$dom->loadHTML($output);
error_reporting($errorLevel);

由于使用自定义处理程序时完全绕过了正常的PHP错误报告,因此使用@操作符是没有意义的,因为当前的error_reporting()级别被完全忽略。您必须在错误处理程序中编写自定义代码来检查当前的error_reporting()级别并相应地处理它,例如:

function my_error_handler() {
  if (error_reporting() == 0) {
    return; // do nothing when error_reporting is disabled.
  }
  // normal error handling here
}

我的假设是,当不使用自定义错误处理程序时,PHP只是默认使用error_reporting()级别,该级别低于所产生的错误。

如果您将error_reporting(E_ALL | E_STRICT);添加到代码的顶部,即使您没有启用自定义错误处理程序,您也会看到相同的错误。