Skip to content

Instantly share code, notes, and snippets.

@WinterSilence
Last active August 29, 2015 14:11
Show Gist options
  • Save WinterSilence/8dd1b5d0aa284380202d to your computer and use it in GitHub Desktop.
Save WinterSilence/8dd1b5d0aa284380202d to your computer and use it in GitHub Desktop.
Enso\Core\ShutdownHandler
<?php
namespace Enso\Core;
/**
* Inline exception handler, displays the error message, source of the exception
* and the stack trace of the error.
*
* @package Enso\Core
* @copyright (c) 2014 WinterSilence
* @license MIT License
*/
class ExceptionHandler
{
// Text format to display
const FORMAT = '%s [%s]: %s ~ %s [%d]';
/**
* @var \Exception
*/
protected $exception;
/**
* @var string
*/
protected $displayCache;
/**
* Create new instance.
*
* @param \Exception $exception
* @return void
*/
public function __construct(\Exception $exception)
{
$this->exception = $exception;
}
/**
* Text to display exception.
*
* @return string
*/
public function display()
{
if (empty($this->displayCache)) {
// Cache text
$this->displayCache = sprintf(
self::FORMAT,
get_class($this->exception),
$this->exception->getCode(),
strip_tags($this->exception->getMessage()),
$this->exception->getFile(),
$this->exception->getLine()
);
}
return $this->displayCache;
}
/**
* Text to display exception.
*
* @return string
*/
public function __toString()
{
return $this->display();
}
}
<?php
namespace Enso\Core;
/**
* Shutdown handler - stack of callbacks.
*
* [!!] debug_backtrace() or debug_print_backtrace() will not work inside
* a shutdown function. If you call exit() within one registered shutdown
* function, processing will stop completely and no other registered shutdown
* functions will be called.
*
* @see http://php.net/function.register-shutdown-function
*
* @package Enso\Core
* @copyright (c) 2014 WinterSilence
* @license MIT License
*/
class ShutdownHandler
{
/**
* @var array Callbacks
*/
protected $handlers = [];
/**
* @var array Types of errors to display at shutdown
*/
protected $displayErrors = [E_PARSE, E_ERROR, E_USER_ERROR];
/**
* Create instance and register as shutdown function.
*
* @param array $errors Shutdown errors
* @return void
*/
public function __construct(array $errors = null)
{
if ($errors) {
$this->displayErrors = $errors;
}
register_shutdown_function(array($this, 'execute'));
}
/**
* Add shutdown handler.
*
* @param callable $callback Callback (string, array, closure)
* @param array $arguments Callback`s arguments
* @param boolean $prepend Add prepend or append?
* @return ShutdownHandler
*/
public function attach(callable $callback, array $arguments = [], $prepend = false)
{
$handler = ['callback' => $callback, 'arguments' => $arguments];
if (!in_array($handler, $this->handlers)) {
if ($prepend) {
array_unshift($this->handlers, $handler);
} else {
$this->handlers[] = $handler;
}
}
return $this;
}
/**
* Delete shutdown handler.
*
* @param callable $callback Callback (string, array, closure)
* @param array $arguments Callback`s arguments
* @return ShutdownHandler
*/
public function detach(callable $callback, array $arguments = [])
{
$handler = ['callback' => $callback, 'arguments' => $arguments];
// Find handler
$key = array_search($handler, $this->handlers);
if ($key !== false) {
unset($this->handlers[$key])
}
return $this;
}
/**
* Return all handlers.
*
* @return array
*/
public function getHandlers()
{
return $this->handlers;
}
/**
* Execute handlers.
*
* @return void
*/
public function execute()
{
try {
foreach ($this->handlers as $handler) {
call_user_func_array($handler['callback'], $handler['arguments']);
}
} catch (\Exception $exception) {
echo new ExceptionHandler($exception);
}
$error = error_get_last();
if ($error && in_array($error['type'], $this->displayErrors))
{
if (ob_get_level()) {
// Clean the output buffer
ob_clean();
}
// Fake an exception for nice debugging
$exception = new \ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line']);
echo new ExceptionHandler($exception);
// Shutdown now to avoid a "death loop"
exit(1);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment