Skip to content

Commit

Permalink
Merge pull request #1 from WebFiori/dev
Browse files Browse the repository at this point in the history
Added Support for Registering Multiple Handlers
  • Loading branch information
usernane authored May 15, 2022
2 parents 63e9d88 + dc5211d commit c2cc6ea
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,53 @@
*
* @author Ibrahim
*/
abstract class AbstractExceptionHandler {
abstract class AbstractHandler {
private $exception;
private $traceArr;
private $name;
private $isCalled;
/**
* Creates new instance of the class.
*/
public function __construct() {
$this->traceArr = [];
$this->name = 'New Handler';
$this->isCalled = false;
}
/**
* Sets the handler as executed.
*
* This method is used to make sure that same handler won't get executed twice.
*
* @param bool $bool True to set it as executed, false to not.
*/
public function setIsExecuted(bool $bool) {
$this->isCalled = $bool;
}
/**
* Checks if the handler was executed once or not.
*
* @return bool If the method returned true, then this means the handler
* was executed.
*/
public function isExecuted() : bool {
return $this->isCalled;
}
/**
* Gives the handler a specific name.
*
* @param string $name The custom name of the handler.
*/
public function setName(string $name) {
$this->name = trim($name);
}
/**
* Returns the name of the handler.
*
* @return string The name of the handler.
*/
public function getName() : string {
return $this->name;
}
/**
* Returns a string that represents the name of the class that an exception
Expand Down Expand Up @@ -65,6 +104,17 @@ public function getTrace() : array {
* The developer can implement this method to handle all thrown exceptions.
*/
public abstract function handle();
/**
* Checks if the handler will be used to handle errors or not.
*
* The developer must implement this method in a way it returns true if the
* handler will get executed. False otherwise.
*/
public abstract function isActive() : bool;
/**
* Checks if the handler will be called in case of error after shutdown.
*/
public abstract function isShutdownHandler() : bool;
/**
* Sets the exception which was thrown by an error on the code.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
*
* @author Ibrahim
*/
class DefaultExceptionsHandler extends AbstractExceptionHandler {
class DefaultHandler extends AbstractHandler {
/**
* Creates new instance of the class.
*/
public function __construct() {
parent::__construct();
$this->setName('Default');
}
/**
* Handles the exception.
Expand All @@ -38,4 +39,13 @@ public function handle() {
}
echo '</pre>';
}

public function isActive(): bool {
return true;
}

public function isShutdownHandler(): bool {
return true;
}

}
101 changes: 88 additions & 13 deletions src/webfiori/error/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @author Ibrahim
*/
class Handler {
private $handlersPool;
/**
* An array which holds one constant that is used to hold the meanings of different
* PHP errors.
Expand Down Expand Up @@ -78,7 +79,7 @@ class Handler {
];
/**
*
* @var AbstractExceptionHandler
* @var AbstractHandler
*/
private $handler;
/**
Expand All @@ -99,11 +100,36 @@ private function __construct() {
});
set_exception_handler(function (Throwable $ex)
{
$class = Handler::get()->handler;
$class->setException($ex);
$class->handle();
foreach (Handler::get()->handlersPool as $h) {

if ($h->isActive()) {
$h->setException($ex);
$h->handle();
$h->setIsExecuted(true);
}
}
});
$this->handler = new DefaultExceptionsHandler();
register_shutdown_function(function () {
$lastErr = error_get_last();

if ($lastErr !== null) {
ob_clean();
$errClass = TraceEntry::extractClassName($lastErr['file']);
$errType = Handler::ERR_TYPES[$lastErr['type']];
$message = $errType['description'].': '.$lastErr['message'].' At '.$errClass.' Line '.$lastErr['line'];
$ex = new ErrorHandlerException($message, $lastErr['type'], $lastErr['file']);
foreach (Handler::get()->handlersPool as $h) {

if ($h->isActive() && $h->isShutdownHandler() && !$h->isExecuted()) {
$h->setException($ex);
$h->handle();
$h->setIsExecuted(true);
}
}
}
});
$this->handlersPool = [];
$this->handlersPool[] = new DefaultHandler();
}
/**
* Returns the instance which is used to handle exceptions and errors.
Expand All @@ -120,19 +146,68 @@ public static function get() {
/**
* Sets a custom handler to handle exceptions.
*
* @param AbstractExceptionHandler $h A class that implements a custom
* @param AbstractHandler $h A class that implements a custom
* handler.
*/
public static function setHandler(AbstractExceptionHandler $h) {
self::get()->handler = $h;
public static function registerHandler(AbstractHandler $h) {
if (!self::hasHandler($h->getName())) {
self::get()->handlersPool[] = $h;
}
}
/**
* Returns the handler instance which is used to handle exceptions.
* Remove a registered errors handler.
*
* @return AbstractExceptionHandler The handler instance which is used to
* handle exceptions.
* @param AbstractHandler $h A class that implements a custom
* handler.
*/
public function getHandler() : AbstractExceptionHandler {
return self::get()->handler;
public static function unregisterHandler(AbstractHandler $h) : bool {
$tempPool = [];
$removed = false;
foreach (self::get()->handlersPool as $handler) {
if ($handler->getName() != $h->getName()) {
$tempPool[] = $handler;
continue;
}
$removed = true;
}
self::get()->handlersPool = $tempPool;
return $removed;
}
/**
* Returns a handler given its name.
*
* @param string $name The name of the handler.
*
* @return AbstractHandler|null If a handler which has the given name is found,
* it will be returned as an object. Other than that, null is returned.
*/
public static function &getHandler(string $name) {
$h = null;
$trimmed = trim($name);

foreach (self::get()->handlersPool as $handler) {
if ($handler->getName() == $trimmed) {
$h = $handler;
break;
}
}
return $h;
}
/**
* Checks if a handler is registered or not given its name.
*
* @param string $name The name of the handler.
*
* @return bool If such handler is registered, the method will return true.
* Other than that, the method will return false.
*/
public static function hasHandler(string $name) : bool {
$trimmed = trim($name);
foreach (self::get()->handlersPool as $handler) {
if ($handler->getName() == $trimmed) {
return true;
}
}
return false;
}
}
4 changes: 2 additions & 2 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
$classesPath = $rootDir.'src'.DS.'webfiori'.DS.'error'.DS;

require_once $classesPath . 'ErrorHandlerException.php';
require_once $classesPath . 'AbstractExceptionHandler.php';
require_once $classesPath . 'DefaultExceptionsHandler.php';
require_once $classesPath . 'AbstractHandler.php';
require_once $classesPath . 'DefaultHandler.php';
require_once $classesPath . 'TraceEntry.php';
require_once $classesPath . 'Handler.php';

Expand Down

0 comments on commit c2cc6ea

Please sign in to comment.