<?php namespace Illuminate\Foundation\Bootstrap;
use ErrorException;
use Illuminate\Contracts\Foundation\Application;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Debug\Exception\FatalErrorException;
class HandleExceptions {
/**
* The application instance.
* Application 实例。
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* Bootstrap the given application.
* 引导给定的应用程序。
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
// 存储 Application 实例
$this->app = $app;
// 报告所有 PHP 错误
error_reporting(-1);
// 设置自定义的错误处理函数
set_error_handler([$this, 'handleError']);
// 设置自定义的异常处理函数
set_exception_handler([$this, 'handleException']);
// 注册 shutdown 处理函数(在脚本终止前回调注册的函数)参考阅读
register_shutdown_function([$this, 'handleShutdown']);
// 若非 testing 环境
if ( ! $app->environment('testing'))
{
// 关闭错误提示输出
ini_set('display_errors', 'Off');
}
}
/**
* Convert a PHP error to an ErrorException.
*
* @param int $level
* @param string $message
* @param string $file
* @param int $line
* @param array $context
* @return void
*
* @throws \ErrorException
*/
public function handleError($level, $message, $file = '', $line = 0, $context = array())
{
if (error_reporting() & $level)
{
throw new ErrorException($message, 0, $level, $file, $line);
}
}
/**
* Handle an uncaught exception from the application.
*
* Note: Most exceptions can be handled via the try / catch block in
* the HTTP and Console kernels. But, fatal error exceptions must
* be handled differently since they are not normal exceptions.
*
* @param \Exception $e
* @return void
*/
public function handleException($e)
{
$this->getExceptionHandler()->report($e);
if ($this->app->runningInConsole())
{
$this->renderForConsole($e);
}
else
{
$this->renderHttpResponse($e);
}
}
/**
* Render an exception to the console.
*
* @param \Exception $e
* @return void
*/
protected function renderForConsole($e)
{
$this->getExceptionHandler()->renderForConsole(new ConsoleOutput, $e);
}
/**
* Render an exception as an HTTP response and send it.
*
* @param \Exception $e
* @return void
*/
protected function renderHttpResponse($e)
{
$this->getExceptionHandler()->render($this->app['request'], $e)->send();
}
/**
* Handle the PHP shutdown event.
*
* @return void
*/
public function handleShutdown()
{
if ( ! is_null($error = error_get_last()) && $this->isFatal($error['type']))
{
$this->handleException($this->fatalExceptionFromError($error, 0));
}
}
/**
* Create a new fatal exception instance from an error array.
*
* @param array $error
* @param int|null $traceOffset
* @return \Symfony\Component\Debug\Exception\FatalErrorException
*/
protected function fatalExceptionFromError(array $error, $traceOffset = null)
{
return new FatalErrorException(
$error['message'], $error['type'], 0, $error['file'], $error['line'], $traceOffset
);
}
/**
* Determine if the error type is fatal.
*
* @param int $type
* @return bool
*/
protected function isFatal($type)
{
return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE]);
}
/**
* Get an instance of the exception handler.
*
* @return \Illuminate\Contracts\Debug\ExceptionHandler
*/
protected function getExceptionHandler()
{
return $this->app->make('Illuminate\Contracts\Debug\ExceptionHandler');
}
}