PHPでHTMLやXMLを解析する際にDOMDocument
を使用することがある。
この時まずは文書を読み込むために以下のような処理を行う。
$html = '<html>...</html>';
$dom = new DOMDocument();
$dom->loadHTML($html); // ここでエラーが発生することがある
この時$dom->loadHTML($html)
の部分でエラーが発生することがある。
これは読み込もうとした文書が不適切な書式で書かれている場合などに発生するものだ。
しかし実際の所世の中のHTMLやXMLが厳密な仕様に従って書かれていることは多くない。
しかし全てが正しくなくても読み込める部分だけでも処理したいという状況はままあるだろう。 そういった場合にこの部分のエラーを無視したいという状況が発生する。
方法のひとつはエラー制御演算子の@
を使うことだ。
$html = '<html>...</html>';
$dom = new DOMDocument();
@$dom->loadHTML($html);
このように@
を付けた式で発生したエラーは無視される。
set_error_handler()を使用して独自のエラーハンドラを登録している場合、このエラー制御演算子@
を付けてもエラーハンドラが呼び出されてしまう。
全て自分で組んだプログラムの場合はその部分の制御をすることもできるが、他人の組んだライブラリの中でエラーハンドラが登録されている場合もある。
@
を付けたのになぜかエラーが無視できないという場合はまずその点を疑ってみたい。
自分の場合、WordPress内の処理で上記のように@
を付けてエラーを無視しようとしたことがある。
しかしどうやらWordPress内に独自のエラーハンドラが定義されているようで、@
を付けてもどうしてもエラーハンドラに飛んでしまうという状況に陥った。
そんな場合はlibxml_use_internal_errors()
という関数を使用してエラーを制御する方法が用意されている。
// libxmlエラーを無効にし、元の設定値を保存する
$internalErrors = libxml_use_internal_errors(true);
$html = '<html>...</html>';
$dom = new DOMDocument();
$dom->loadHTML($html); // ここでエラーが発生することがある
/*
読み込んだ文書に対して処理を行う
*/
// 独自にエラーを処理したい場合はここでエラーを取得する
$errors = libxml_get_errors();
// libxmlエラーの制御状態を元に戻す
libxml_use_internal_errors($internalErrors);
// 蓄積されたエラーをクリアする
libxml_clear_errors();
libxml_use_internal_errors()
を引数true
で呼びだすと「libxmlエラーは全て自分で処理するのでシステムはエラーを無視せよ」という指示が行われる。
この場合も内部ではエラーが蓄積されており、libxml_get_errors()
を呼びだせばエラー情報を取得することができるようになっている。
このエラー情報はlibxml_use_internal_errors()
を引数false
で呼びだすか、libxml_clear_errors()
を呼びだすまで蓄積され続ける。
上記のコードではlibxml_use_internal_errors()
の戻り値から元の設定値を$internalErrors
に保存し、最後に設定値を元に戻している。
しかし元々の設定値がtrue
である可能性もあり、その場合はエラーが残ったままになる。
そのため必要な処理を終えたら最後にlibxml_clear_errors()
を呼び出しておくべきだろう。