refactored error handling for better architecture.
This commit is contained in:
parent
e2c69d0c84
commit
5c3c2e2d9c
119
system/error.php
119
system/error.php
|
@ -1,119 +0,0 @@
|
||||||
<?php namespace System;
|
|
||||||
|
|
||||||
class Error {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Human-readable error levels and descriptions.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public static $levels = array(
|
|
||||||
0 => 'Error',
|
|
||||||
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 => 'Runtime Notice'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an exception.
|
|
||||||
*
|
|
||||||
* @param Exception $e
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function handle($e)
|
|
||||||
{
|
|
||||||
// Clear the output buffer so nothing is sent to the browser except the error
|
|
||||||
// message. This prevents any views that have already been rendered from being
|
|
||||||
// in an incomplete or erroneous state.
|
|
||||||
if (ob_get_level() > 0) ob_clean();
|
|
||||||
|
|
||||||
$severity = (array_key_exists($e->getCode(), static::$levels)) ? static::$levels[$e->getCode()] : $e->getCode();
|
|
||||||
|
|
||||||
$message = static::format($e);
|
|
||||||
|
|
||||||
if (Config::get('error.log'))
|
|
||||||
{
|
|
||||||
call_user_func(Config::get('error.logger'), $severity, $message, $e->getTraceAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
static::show($e, $severity, $message);
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the error message for a given exception.
|
|
||||||
*
|
|
||||||
* @param Exception $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function format($e)
|
|
||||||
{
|
|
||||||
$file = str_replace(array(APP_PATH, SYS_PATH), array('APP_PATH/', 'SYS_PATH/'), $e->getFile());
|
|
||||||
|
|
||||||
return rtrim($e->getMessage(), '.').' in '.$file.' on line '.$e->getLine().'.';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the error view.
|
|
||||||
*
|
|
||||||
* @param Exception $e
|
|
||||||
* @param string $severity
|
|
||||||
* @param string $message
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private static function show($e, $severity, $message)
|
|
||||||
{
|
|
||||||
if (Config::get('error.detail'))
|
|
||||||
{
|
|
||||||
$view = View::make('error/exception')
|
|
||||||
->bind('severity', $severity)
|
|
||||||
->bind('message', $message)
|
|
||||||
->bind('line', $e->getLine())
|
|
||||||
->bind('trace', $e->getTraceAsString())
|
|
||||||
->bind('contexts', static::context($e->getFile(), $e->getLine()));
|
|
||||||
|
|
||||||
Response::make($view, 500)->send();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Response::error('500')->send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the code surrounding a given line in a file.
|
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
* @param int $line
|
|
||||||
* @param int $padding
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private static function context($path, $line, $padding = 5)
|
|
||||||
{
|
|
||||||
if (file_exists($path))
|
|
||||||
{
|
|
||||||
$file = file($path, FILE_IGNORE_NEW_LINES);
|
|
||||||
|
|
||||||
array_unshift($file, '');
|
|
||||||
|
|
||||||
if (($start = $line - $padding) < 0) $start = 0;
|
|
||||||
|
|
||||||
if (($length = ($line - $start) + $padding + 1) < 0) $length = 0;
|
|
||||||
|
|
||||||
return array_slice($file, $start, $length, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php namespace System\Exception;
|
||||||
|
|
||||||
|
use System\View;
|
||||||
|
use System\Config;
|
||||||
|
use System\Response;
|
||||||
|
|
||||||
|
class Handler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exception wrapper for the exception being handled.
|
||||||
|
*
|
||||||
|
* @var Wrapper
|
||||||
|
*/
|
||||||
|
public $exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception handler instance.
|
||||||
|
*
|
||||||
|
* @param Exception $e
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($e)
|
||||||
|
{
|
||||||
|
$this->exception = new Wrapper($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception handler instance.
|
||||||
|
*
|
||||||
|
* @param Exception $e
|
||||||
|
* @return Handler
|
||||||
|
*/
|
||||||
|
public static function make($e)
|
||||||
|
{
|
||||||
|
return new static($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the exception and display the error report.
|
||||||
|
*
|
||||||
|
* The exception will be logged if error logging is enabled.
|
||||||
|
*
|
||||||
|
* The output buffer will be cleaned so nothing is sent to the browser except the
|
||||||
|
* error message. This prevents any views that have already been rendered from
|
||||||
|
* being shown in an incomplete or erroneous state.
|
||||||
|
*
|
||||||
|
* After the exception is displayed, the request will be halted.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
if (ob_get_level() > 0) ob_clean();
|
||||||
|
|
||||||
|
if (Config::get('error.log')) $this->log();
|
||||||
|
|
||||||
|
$this->get_response(Config::get('error.detail'))->send();
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log the exception using the logger closure specified in the error configuration.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function log()
|
||||||
|
{
|
||||||
|
$parameters = array(
|
||||||
|
$this->exception->severity(),
|
||||||
|
$this->exception->message(),
|
||||||
|
$this->exception->getTraceAsString(),
|
||||||
|
);
|
||||||
|
|
||||||
|
call_user_func_array(Config::get('error.logger'), $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error report response for the exception.
|
||||||
|
*
|
||||||
|
* @param bool $detailed
|
||||||
|
* @return Resposne
|
||||||
|
*/
|
||||||
|
private function get_response($detailed)
|
||||||
|
{
|
||||||
|
return ($detailed) ? $this->detailed_response() : $this->generic_response();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the detailed error report for the exception.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
private function detailed_response()
|
||||||
|
{
|
||||||
|
$data = array(
|
||||||
|
'severity' => $this->exception->severity(),
|
||||||
|
'message' => $this->exception->message(),
|
||||||
|
'line' => $this->exception->getLine(),
|
||||||
|
'trace' => $this->exception->getTraceAsString(),
|
||||||
|
'contexts' => $this->exception->context(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Response::make(View::make('error.exception', $data), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the generic error report for the exception.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
private function generic_response()
|
||||||
|
{
|
||||||
|
return Response::error('500');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php namespace System\Exception;
|
||||||
|
|
||||||
|
use System\File;
|
||||||
|
|
||||||
|
class Wrapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The exception being wrapped.
|
||||||
|
*
|
||||||
|
* @var Exception
|
||||||
|
*/
|
||||||
|
public $exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Human-readable error levels and descriptions.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $levels = array(
|
||||||
|
0 => 'Error',
|
||||||
|
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 => 'Runtime Notice'
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new exception wrapper instance.
|
||||||
|
*
|
||||||
|
* @param Exception $e
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($e)
|
||||||
|
{
|
||||||
|
$this->exception = $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a human-readable version of the exception error code.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function severity()
|
||||||
|
{
|
||||||
|
if (array_key_exists($this->exception->getCode(), $this->levels))
|
||||||
|
{
|
||||||
|
return $this->levels[$this->exception->getCode()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->exception->getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the exception error message formatted for use by Laravel.
|
||||||
|
*
|
||||||
|
* The exception file paths will be shortened, and the file name and line number
|
||||||
|
* will be added to the exception message.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function message()
|
||||||
|
{
|
||||||
|
$file = str_replace(array(APP_PATH, SYS_PATH), array('APP_PATH/', 'SYS_PATH/'), $this->exception->getFile());
|
||||||
|
|
||||||
|
return rtrim($this->exception->getMessage(), '.').' in '.$file.' on line '.$this->exception->getLine().'.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the code surrounding the line where the exception occurred.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function context()
|
||||||
|
{
|
||||||
|
return File::snapshot($this->exception->getFile(), $this->exception->getLine());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic Method to handle getting properties from the exception.
|
||||||
|
*/
|
||||||
|
public function __get($key)
|
||||||
|
{
|
||||||
|
return $this->exception->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic Method to handle setting properties on the exception.
|
||||||
|
*/
|
||||||
|
public function __set($key, $value)
|
||||||
|
{
|
||||||
|
$this->exception->$key = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic Method to pass function calls to the exception.
|
||||||
|
*/
|
||||||
|
public function __call($method, $parameters)
|
||||||
|
{
|
||||||
|
return call_user_func_array(array($this->exception, $method), $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,6 +48,29 @@ public static function extension($path)
|
||||||
return pathinfo($path, PATHINFO_EXTENSION);
|
return pathinfo($path, PATHINFO_EXTENSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the lines surrounding a given line in a file.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $line
|
||||||
|
* @param int $padding
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function snapshot($path, $line, $padding = 5)
|
||||||
|
{
|
||||||
|
if ( ! file_exists($path)) return array();
|
||||||
|
|
||||||
|
$file = file($path, FILE_IGNORE_NEW_LINES);
|
||||||
|
|
||||||
|
array_unshift($file, '');
|
||||||
|
|
||||||
|
if (($start = $line - $padding) < 0) $start = 0;
|
||||||
|
|
||||||
|
if (($length = ($line - $start) + $padding + 1) < 0) $length = 0;
|
||||||
|
|
||||||
|
return array_slice($file, $start, $length, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a file MIME type by extension.
|
* Get a file MIME type by extension.
|
||||||
*
|
*
|
||||||
|
|
|
@ -59,25 +59,27 @@
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
set_exception_handler(function($e)
|
set_exception_handler(function($e)
|
||||||
{
|
{
|
||||||
require_once SYS_PATH.'error'.EXT;
|
require_once SYS_PATH.'exception/handler'.EXT;
|
||||||
|
|
||||||
Error::handle($e);
|
Exception\Handler::make($e)->handle();
|
||||||
});
|
});
|
||||||
|
|
||||||
set_error_handler(function($number, $error, $file, $line)
|
set_error_handler(function($number, $error, $file, $line)
|
||||||
{
|
{
|
||||||
require_once SYS_PATH.'error'.EXT;
|
require_once SYS_PATH.'exception/handler'.EXT;
|
||||||
|
|
||||||
Error::handle(new \ErrorException($error, $number, 0, $file, $line));
|
Exception\Handler::make(new \ErrorException($error, $number, 0, $file, $line))->handle();
|
||||||
});
|
});
|
||||||
|
|
||||||
register_shutdown_function(function()
|
register_shutdown_function(function()
|
||||||
{
|
{
|
||||||
if ( ! is_null($error = error_get_last()))
|
if ( ! is_null($error = error_get_last()))
|
||||||
{
|
{
|
||||||
require_once SYS_PATH.'error'.EXT;
|
require_once SYS_PATH.'exception/handler'.EXT;
|
||||||
|
|
||||||
Error::handle(new \ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']));
|
extract($error);
|
||||||
|
|
||||||
|
Exception\Handler::make(new \ErrorException($message, $type, 0, $file, $line))->handle();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue