set_error_handler()
のコールバック関数でエラー情報を一旦 ErrorException
にしておくと、いろいろ恩恵が得られるというお話。
<?php
// ErrorExceptionをもう少し便利にしたクラス
class MyErrorException extends ErrorException
{
protected static $severities = [
E_ERROR => 'ERROR',
E_WARNING => 'WARNING',
E_PARSE => 'PARSING ERROR',
E_NOTICE => 'NOTICE',
E_CORE_ERROR => 'CORE ERROR',
E_CORE_WARNING => 'CORE WARNING',
E_COMPILE_ERROR => 'COMPILE ERROR',
E_COMPILE_WARNING => 'COMPILE WARNING',
E_USER_ERROR => 'USER ERROR',
E_USER_WARNING => 'USER WARNING',
E_USER_NOTICE => 'USER NOTICE',
E_STRICT => 'STRICT NOTICE',
E_RECOVERABLE_ERROR => 'RECOVERABLE ERROR',
E_DEPRECATED => 'DEPRECATED',
E_USER_DEPRECATED => 'USER DEPRECATED',
];
/**
* return full exception message
* @return string
*/
public function getFullMessage()
{
return sprintf('%s: %s in %s on line %u', $this->getSeverityString(), $this->getMessage(), $this->getFile(), $this->getLine());
}
/**
* return the exception severity as string
* @return string
*/
public function getSeverityString()
{
return $this->_severityToString($this->getSeverity());
}
/**
* return severity as string
* @param int $severity
* @return string
*/
protected function _severityToString($severity)
{
if ( array_key_exists($severity, static::$severities) === true )
{
return static::$severities[$severity];
}
return 'UNKNOWN ERROR('.$severity.')';
}
}
// エラーハンドラーの登録
set_error_handler(function($severity, $message, $file, $line) {
// 一度例外オブジェクトにすると、エラーをオブジェクト指向的に扱えます。
// 例外オブジェクトですが必ずしも throw する必要はないです。
$errorException = new MyErrorException($message, 0, $severity, $file, $line);
// ErrorExceptionを継承したクラスを使うこともできます。
echo $errorException->getFullMessage(), PHP_EOL;
// オブジェクトを文字列にキャストすると、バックトレースもできます。
echo $errorException;
// 任意のファイルに書き込んだりとか。
error_log($errorException, 3, '/tmp/error_log');
// オブザーバパターンを使って、オブザーバに知らせるとか。
observe_error($errorException);
// 例外を投げて処理を中断したり。
throw $errorException;
});
// オブザーバ
function observe_error(ErrorException $errorException) {
// ErrorException を使えば、コールバック関数側で、引数に型を指定できるので、契約プログラミング(Programming By Contract)的な安心感があります。
// function($severity, $message, $file, $line) {} のような引数いっぱいのコールバックを書かなくてよくなります。
// ErrorExceptionの処理が続く...
}
// エラーを起こす
trigger_error('エラーだよ!');