diff --git a/phpunit.xml b/phpunit.xml
index 2735502..365b49a 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -5,6 +5,8 @@
./src/webfiori/error/TraceEntry.php
+ ./src/webfiori/error/Handler.php
+ ./src/webfiori/error/AbstractHandler.php
diff --git a/tests/webfiori/tests/error/HandlerTest.php b/tests/webfiori/tests/error/HandlerTest.php
index 06815a1..de68889 100644
--- a/tests/webfiori/tests/error/HandlerTest.php
+++ b/tests/webfiori/tests/error/HandlerTest.php
@@ -2,10 +2,11 @@
namespace webfiori\tests\error;
-namespace webfiori\tests\error;
+require_once 'SampleHandler1.php';
+require_once 'SampleHandler2.php';
use PHPUnit\Framework\TestCase;
-use webfiori\error\TraceEntry;
+use webfiori\error\ErrorHandlerException;
use webfiori\error\Handler;
/**
* Description of HandlerTest
@@ -17,7 +18,44 @@ class HandlerTest extends TestCase {
* @test
*/
public function test00() {
+ $this->expectException(ErrorHandlerException::class);
+ $this->expectExceptionMessage('An exception caused by an error. Run-time warning: Undefined variable $y at HandlerTest Line 24');
+ $h = Handler::get();
+ $x = $y;
+ }
+ /**
+ * @test
+ */
+ public function test01() {
+ $h = Handler::get();
+ $this->assertFalse($h->hasHandler('New Handler'));
+ $h->registerHandler(new SampleHandler1());
+ $this->assertTrue($h->hasHandler('New Handler'));
+ $h->unregisterHandler($h->getHandler('New Handler'));
+ $this->assertFalse($h->hasHandler('New Handler'));
+ }
+ /**
+ * @test
+ */
+ public function test02() {
+ $h = Handler::get();
+ $h->reset();
+ $h->registerHandler(new SampleHandler1());
+ $this->assertFalse(defined('SampleHandler1'));
+ $h->invokExceptionHandler();
+ $this->assertTrue(defined('SampleHandler1'));
+ }
+ /**
+ * @test
+ */
+ public function test03() {
$h = Handler::get();
- $this->assertTrue(true);
+ $h->reset();
+ $h->registerHandler(new SampleHandler2());
+ $this->assertFalse(defined('SampleHandler2'));
+ $h->invokExceptionHandler();
+ $this->assertFalse(defined('SampleHandler2'));
+ $h->invokShutdownHandler();
+ $this->assertTrue(defined('SampleHandler2'));
}
}
diff --git a/tests/webfiori/tests/error/SampleHandler1.php b/tests/webfiori/tests/error/SampleHandler1.php
new file mode 100644
index 0000000..740c330
--- /dev/null
+++ b/tests/webfiori/tests/error/SampleHandler1.php
@@ -0,0 +1,23 @@
+getException()->getFile());
+ return TraceEntry::extractClassName($this->getException() !== null ? $this->getException()->getFile() : 'X');
}
/**
* Returns exception error code.
@@ -43,9 +43,9 @@ public function getCode() : string {
/**
* Returns an object that represents the exception which was thrown.
*
- * @return Throwable An object that represents the exception which was thrown.
+ * @return Throwable|null An object that represents the exception which was thrown.
*/
- public function getException() : Throwable {
+ public function getException() {
return $this->exception;
}
/**
@@ -54,7 +54,7 @@ public function getException() : Throwable {
* @return string The number of line at which the exception was thrown at.
*/
public function getLine() : string {
- return $this->getException()->getLine().'';
+ return $this->getException() !== null ? $this->getException()->getLine().'' : 'X';
}
/**
* Returns a string that represents exception message.
@@ -62,7 +62,7 @@ public function getLine() : string {
* @return string A string that represents exception message.
*/
public function getMessage() : string {
- return $this->getException()->getMessage();
+ return $this->getException() !== null ? $this->getException()->getMessage() : 'No Message';
}
/**
* Returns the name of the handler.
@@ -116,6 +116,9 @@ public function isExecuting() : bool {
}
/**
* Checks if the handler will be called in case of error after shutdown.
+ *
+ * Note that if the handler is set as shutdown handler, it will not
+ * get executed during normal events.
*/
public abstract function isShutdownHandler() : bool;
/**
diff --git a/webfiori/error/Handler.php b/webfiori/error/Handler.php
index 4569500..92bec28 100644
--- a/webfiori/error/Handler.php
+++ b/webfiori/error/Handler.php
@@ -1,6 +1,7 @@
isErrOccured = false;
- set_error_handler(function (int $errno, string $errString, string $errFile, int $errLine)
- {
+ $this->errToExceptionHandler = function (int $errno, string $errString, string $errFile, int $errLine) {
+ //Convert errors to exceptions
$errClass = TraceEntry::extractClassName($errFile);
$errType = Handler::ERR_TYPES[$errno];
$message = 'An exception caused by an error. '.$errType['description'].': '.$errString.' at '.$errClass.' Line '.$errLine;
throw new ErrorHandlerException($message, $errno, $errFile);
- });
- set_exception_handler(function (Throwable $ex)
- {
- $this->lastException = $ex;
+ };
+ $this->exceptionsHandler = function (Throwable $ex = null) {
+ Handler::get()->lastException = $ex;
foreach (Handler::get()->handlersPool as $h) {
- if ($h->isActive()) {
- $h->setException($ex);
+ if ($h->isActive() && !$h->isShutdownHandler()) {
+ if ($ex !== null) {
+ $h->setException($ex);
+ }
$h->setIsExecuting(true);
$h->handle();
$h->setIsExecuting(false);
$h->setIsExecuted(true);
}
}
- });
- register_shutdown_function(function ()
- {
+ };
+ $this->shutdownFunction = function () {
if ($this->lastException !== null) {
if (ob_get_length()) {
ob_clean();
@@ -133,10 +136,28 @@ private function __construct() {
}
}
}
- });
+ };
+ $this->isErrOccured = false;
+ set_exception_handler($this->exceptionsHandler);
+ set_error_handler($this->errToExceptionHandler);
+
+ register_shutdown_function($this->shutdownFunction);
$this->handlersPool = [];
$this->handlersPool[] = new DefaultHandler();
}
+ public function invokShutdownHandler() {
+ self::get()->lastException = new Exception();
+ call_user_func(self::get()->shutdownFunction);
+ }
+ public function invokExceptionHandler() {
+ call_user_func(self::get()->exceptionsHandler);
+ }
+ public static function reset() {
+ $h = self::get();
+ $h->handlersPool = [];
+ $h->handlersPool[] = new DefaultHandler();
+ set_error_handler($h->errToExceptionHandler);
+ }
/**
* Returns a handler given its name.
*