From aed9774b9eaff51223dc74f93b4245f9501eb399 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Fri, 12 Nov 2021 18:03:45 +0100 Subject: [PATCH 1/5] one should be able to prepend exceptions handlers --- src/Weew/ErrorHandler/ErrorHandler.php | 141 ++++++++++++------ tests/Weew/ErrorHandler/ErrorHandlerTest.php | 61 +++++++- .../Stubs/FakeExceptionHandler.php | 7 + 3 files changed, 159 insertions(+), 50 deletions(-) diff --git a/src/Weew/ErrorHandler/ErrorHandler.php b/src/Weew/ErrorHandler/ErrorHandler.php index 124f3e4..65fb518 100644 --- a/src/Weew/ErrorHandler/ErrorHandler.php +++ b/src/Weew/ErrorHandler/ErrorHandler.php @@ -7,11 +7,12 @@ use Weew\ErrorHandler\Errors\IError; use Weew\ErrorHandler\Exceptions\InvalidHandlerType; use Weew\ErrorHandler\Handlers\ExceptionHandler; -use Weew\ErrorHandler\Handlers\NativeErrorHandler; use Weew\ErrorHandler\Handlers\IExceptionHandler; use Weew\ErrorHandler\Handlers\INativeErrorHandler; +use Weew\ErrorHandler\Handlers\NativeErrorHandler; -class ErrorHandler implements IErrorHandler { +class ErrorHandler implements IErrorHandler +{ /** * @var ErrorConverter */ @@ -62,7 +63,8 @@ class ErrorHandler implements IErrorHandler { * * @param bool $convertErrorsToExceptions */ - public function __construct($convertErrorsToExceptions = false) { + public function __construct($convertErrorsToExceptions = false) + { $this->errorConverter = $this->createErrorConverter(); $this->convertErrorsToExceptions($convertErrorsToExceptions); } @@ -70,7 +72,8 @@ public function __construct($convertErrorsToExceptions = false) { /** * Enable exception, error and fatal error handling. */ - public function enable() { + public function enable() + { $this->enableExceptionHandling(); $this->enableErrorHandling(); } @@ -78,7 +81,8 @@ public function enable() { /** * Enable exception handling. */ - public function enableExceptionHandling() { + public function enableExceptionHandling() + { if ($this->isExceptionHandlingEnabled()) { return; } @@ -90,7 +94,8 @@ public function enableExceptionHandling() { /** * Enable handling of native PHP errors. */ - public function enableErrorHandling() { + public function enableErrorHandling() + { $this->enableRecoverableErrorHandling(); $this->enableFatalErrorHandling(); } @@ -98,7 +103,8 @@ public function enableErrorHandling() { /** * Enable regular error handling. */ - public function enableRecoverableErrorHandling() { + public function enableRecoverableErrorHandling() + { if ($this->isRecoverableErrorHandlingEnabled()) { return; } @@ -117,7 +123,8 @@ public function enableRecoverableErrorHandling() { /** * Enable fatal/non-recoverable error handling. */ - public function enableFatalErrorHandling() { + public function enableFatalErrorHandling() + { if ($this->isFatalErrorHandlingEnabled()) { return; } @@ -132,36 +139,41 @@ public function enableFatalErrorHandling() { /** * @return bool */ - public function isExceptionHandlingEnabled() { + public function isExceptionHandlingEnabled() + { return $this->isExceptionHandlingEnabled; } /** * @return bool */ - public function isErrorHandlingEnabled() { + public function isErrorHandlingEnabled() + { return $this->isRecoverableErrorHandlingEnabled() - && $this->isFatalErrorHandlingEnabled(); + && $this->isFatalErrorHandlingEnabled(); } /** * @return bool */ - public function isRecoverableErrorHandlingEnabled() { + public function isRecoverableErrorHandlingEnabled() + { return $this->isRecoverableErrorHandlingEnabled; } /** * @return bool */ - public function isFatalErrorHandlingEnabled() { + public function isFatalErrorHandlingEnabled() + { return $this->isFatalErrorHandlingEnabled; } /** * @return bool */ - public function isConvertingErrorsToExceptions() { + public function isConvertingErrorsToExceptions() + { return $this->isConvertingErrorsToExceptions; } @@ -172,21 +184,32 @@ public function isConvertingErrorsToExceptions() { * * @throws InvalidHandlerType */ - public function addExceptionHandler($handler) { - if ( ! $handler instanceof IExceptionHandler && ! is_callable($handler)) { - throw new InvalidHandlerType( - s('Exception handler must be a callable or an instance of %s.', - IExceptionHandler::class) - ); - } - - if (is_callable($handler)) { - $handler = $this->createExceptionHandler($handler); - } + public function addExceptionHandler($handler) + { + $handler = $this->createHandlerForException($handler); $this->exceptionHandlers[] = $handler; } + /** + * Prepend an error handler for exceptions. + * + * @param callable|IExceptionHandler $handler + * + * @throws InvalidHandlerType + */ + public function prependExceptionHandler($handler) + { + + + $handler = $this->createHandlerForException($handler); + + $wtf = array_reverse($this->exceptionHandlers); + $wtf[] = $handler; + + $this->exceptionHandlers = array_reverse($wtf); + } + /** * Add an error handler for all kinds of native PHP errors. * @@ -194,7 +217,8 @@ public function addExceptionHandler($handler) { * * @throws InvalidHandlerType */ - public function addErrorHandler($handler) { + public function addErrorHandler($handler) + { $this->addRecoverableErrorHandler($handler); $this->addFatalErrorHandler($handler); } @@ -206,8 +230,9 @@ public function addErrorHandler($handler) { * * @throws InvalidHandlerType */ - public function addRecoverableErrorHandler($handler) { - if ( ! $handler instanceof INativeErrorHandler && ! is_callable($handler)) { + public function addRecoverableErrorHandler($handler) + { + if (!$handler instanceof INativeErrorHandler && !is_callable($handler)) { throw new InvalidHandlerType( s('Recoverable error handler must be a callable or an instance of %s.', INativeErrorHandler::class) @@ -228,8 +253,9 @@ public function addRecoverableErrorHandler($handler) { * * @throws InvalidHandlerType */ - public function addFatalErrorHandler($handler) { - if ( ! $handler instanceof INativeErrorHandler && ! is_callable($handler)) { + public function addFatalErrorHandler($handler) + { + if (!$handler instanceof INativeErrorHandler && !is_callable($handler)) { throw new InvalidHandlerType( s('Fatal error handler must be a callable or an instance of %s.', INativeErrorHandler::class) @@ -248,11 +274,12 @@ public function addFatalErrorHandler($handler) { * * @throws Throwable */ - public function handleException(Throwable $ex) { + public function handleException(Throwable $ex) + { foreach ($this->getExceptionHandlers() as $handler) { if ($handler->isEnabled()) { try { - if ( ! $handler->supports($ex)) { + if (!$handler->supports($ex)) { continue; } @@ -278,7 +305,8 @@ public function handleException(Throwable $ex) { /** * @param IError $error */ - public function handleError(IError $error) { + public function handleError(IError $error) + { if ($error->isRecoverable()) { $this->handleRecoverableError($error); } else { @@ -291,7 +319,8 @@ public function handleError(IError $error) { * * @return bool|void */ - public function handleRecoverableError(IError $error) { + public function handleRecoverableError(IError $error) + { // ignore error caused by a rethrown exception if ($this->ignoreRethrownException) { $this->ignoreRethrownException = false; @@ -326,7 +355,8 @@ public function handleRecoverableError(IError $error) { * * @return bool|void */ - public function handleFatalError(IError $error) { + public function handleFatalError(IError $error) + { // ignore error caused by a rethrown exception if ($this->ignoreRethrownException) { $this->ignoreRethrownException = false; @@ -361,7 +391,8 @@ public function handleFatalError(IError $error) { /** * @param bool $convertErrorsToExceptions */ - public function convertErrorsToExceptions($convertErrorsToExceptions) { + public function convertErrorsToExceptions($convertErrorsToExceptions) + { $this->isConvertingErrorsToExceptions = $convertErrorsToExceptions; if ($convertErrorsToExceptions) { @@ -372,21 +403,24 @@ public function convertErrorsToExceptions($convertErrorsToExceptions) { /** * @return IExceptionHandler[] */ - public function getExceptionHandlers() { + public function getExceptionHandlers() + { return $this->exceptionHandlers; } /** * @return INativeErrorHandler[] */ - public function getRecoverableErrorHandlers() { + public function getRecoverableErrorHandlers() + { return $this->recoverableErrorHandlers; } /** * @return INativeErrorHandler[] */ - public function getFatalErrorHandlers() { + public function getFatalErrorHandlers() + { return $this->fatalErrorHandlers; } @@ -395,7 +429,8 @@ public function getFatalErrorHandlers() { * * @return IExceptionHandler */ - protected function createExceptionHandler(callable $handler) { + protected function createExceptionHandler(callable $handler) + { return new ExceptionHandler($handler); } @@ -404,14 +439,36 @@ protected function createExceptionHandler(callable $handler) { * * @return INativeErrorHandler */ - protected function createNativeErrorHandler(callable $handler) { + protected function createNativeErrorHandler(callable $handler) + { return new NativeErrorHandler($handler); } /** * @return ErrorConverter */ - protected function createErrorConverter() { + protected function createErrorConverter() + { return new ErrorConverter(); } + + /** + * @param $handler + * @return callable|ExceptionHandler|IExceptionHandler + * @throws InvalidHandlerType + */ + private function createHandlerForException($handler) + { + if (!$handler instanceof IExceptionHandler && !is_callable($handler)) { + throw new InvalidHandlerType( + s('Exception handler must be a callable or an instance of %s.', + IExceptionHandler::class) + ); + } + + if (is_callable($handler)) { + $handler = $this->createExceptionHandler($handler); + } + return $handler; + } } diff --git a/tests/Weew/ErrorHandler/ErrorHandlerTest.php b/tests/Weew/ErrorHandler/ErrorHandlerTest.php index 2d7ed2c..858daad 100644 --- a/tests/Weew/ErrorHandler/ErrorHandlerTest.php +++ b/tests/Weew/ErrorHandler/ErrorHandlerTest.php @@ -83,6 +83,37 @@ public function test_enable_error_handling() $this->assertTrue($handler->isErrorHandlingEnabled()); } + /** + * @throws InvalidHandlerType + */ + public function test_prepend_and_get_exception_handlers() + { + $handler = new ErrorHandler(); + + $this->assertEmpty($handler->getExceptionHandlers()); + + $handler->addExceptionHandler(new FakeExceptionHandler(1)); + + $this->assertCount(1, $handler->getExceptionHandlers()); + + $handler->addExceptionHandler(new FakeExceptionHandler(2)); + $this->assertCount(2, $handler->getExceptionHandlers()); + $handler->addExceptionHandler(new FakeExceptionHandler(3)); + $this->assertCount(3, $handler->getExceptionHandlers()); +// $this->assertOrder($handler, [1, 2, 3], 'Die ersten drei werden normal hinzugefügt'); + + + + + $handler->prependExceptionHandler(new FakeExceptionHandler(42)); + $this->assertCount(4, $handler->getExceptionHandlers()); + $this->assertOrder($handler, [42, 1, 2, 3], '42 sollte jetzt am Anfang sein'); + $handler->prependExceptionHandler(new FakeExceptionHandler(199)); + $this->assertCount(5, $handler->getExceptionHandlers()); + $this->assertOrder($handler, [199, 42, 1, 2, 3], '199 sollte jetzt am Anfang sein'); + } + + public function test_add_and_get_exception_handlers() { $handler = new ErrorHandler(); @@ -280,7 +311,7 @@ public function test_handle_fatal_error_with_error_to_exception_conversion_enabl public function test_handle_error_with_fatal_error() { - $handler = new ErrorHandler(); + $handler = new ErrorHandler(); $fatalError = new FatalError(ErrorType::PARSE, 'foo', 'bar', 'baz'); ob_start(); @@ -292,7 +323,7 @@ public function test_handle_error_with_fatal_error() public function test_handle_error_with_recoverable_error() { - $handler = new ErrorHandler(); + $handler = new ErrorHandler(); $recoverableError = new RecoverableError(ErrorType::ERROR, 'foo', 'bar', 'baz'); $handler->handleError($recoverableError); @@ -302,10 +333,10 @@ public function test_handle_error_with_recoverable_error() public function test_unhandled_exception_with_error_handling_enabled() { - $handler = new ErrorHandler(); - $exception = new Exception(); + $handler = new ErrorHandler(); + $exception = new Exception(); $recoverableError = new RecoverableError(ErrorType::ERROR, 'foo', 'bar', 'baz'); - $fatalError = new FatalError(ErrorType::PARSE, 'foo', 'bar', 'baz'); + $fatalError = new FatalError(ErrorType::PARSE, 'foo', 'bar', 'baz'); try { $handler->handleException($exception); @@ -319,7 +350,7 @@ public function test_unhandled_exception_with_error_handling_enabled() public function test_exception_from_exception_handler_is_handled() { - $handler = new ErrorHandler(); + $handler = new ErrorHandler(); $exception = new Exception(); $handler->addExceptionHandler(function (Exception $ex) { @@ -334,7 +365,7 @@ public function test_exception_from_exception_handler_is_handled() public function test_fatal_error_from_fatal_error_handler_is_handled() { - $handler = new ErrorHandler(); + $handler = new ErrorHandler(); $fatalError = new FatalError(ErrorType::PARSE, 'foo', 'bar', 'baz'); $handler->addFatalErrorHandler(function (IError $error) { @@ -351,7 +382,7 @@ public function test_fatal_error_from_fatal_error_handler_is_handled() public function test_exception_from_recoverable_error_handler_is_handled() { - $handler = new ErrorHandler(); + $handler = new ErrorHandler(); $recoverableError = new RecoverableError(ErrorType::ERROR, 'foo', 'bar', 'baz'); $handler->addRecoverableErrorHandler(function (IError $error) { @@ -363,4 +394,18 @@ public function test_exception_from_recoverable_error_handler_is_handled() } catch (Exception $ex) { } } + + /** + * @param ErrorHandler $handler + * @param array $expectedOrder + * @return void + */ + private function assertOrder(ErrorHandler $handler, array $expectedOrder, string $message = '') + { + $ids = array_map(function (FakeExceptionHandler $fh) { + return $fh->id; + }, $handler->getExceptionHandlers()); + + $this->assertEquals($expectedOrder, $ids, $message); + } } diff --git a/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php b/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php index c3592a4..76f938d 100644 --- a/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php +++ b/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php @@ -6,6 +6,13 @@ use Weew\ErrorHandler\Handlers\IExceptionHandler; class FakeExceptionHandler implements IExceptionHandler { + public $id; + + public function __construct($id = 1) + { + $this->id = $id; + } + private $enabled = true; public function supports(Throwable $ex) { From 2d053cdde6dbe307424b9502de3aa777b648e726 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Fri, 12 Nov 2021 18:05:32 +0100 Subject: [PATCH 2/5] refactor --- src/Weew/ErrorHandler/ErrorHandler.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Weew/ErrorHandler/ErrorHandler.php b/src/Weew/ErrorHandler/ErrorHandler.php index 65fb518..6ae39c4 100644 --- a/src/Weew/ErrorHandler/ErrorHandler.php +++ b/src/Weew/ErrorHandler/ErrorHandler.php @@ -200,14 +200,8 @@ public function addExceptionHandler($handler) */ public function prependExceptionHandler($handler) { - - $handler = $this->createHandlerForException($handler); - - $wtf = array_reverse($this->exceptionHandlers); - $wtf[] = $handler; - - $this->exceptionHandlers = array_reverse($wtf); + array_unshift($this->exceptionHandlers, $handler); } /** From b3d992f35077fe0b6dc5c20c1a1201959ca5d986 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Fri, 12 Nov 2021 18:13:13 +0100 Subject: [PATCH 3/5] refactor --- tests/Weew/ErrorHandler/ErrorHandlerTest.php | 42 +++++++++++-------- .../Stubs/FakeExceptionHandler.php | 8 ++++ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/tests/Weew/ErrorHandler/ErrorHandlerTest.php b/tests/Weew/ErrorHandler/ErrorHandlerTest.php index 858daad..7270b17 100644 --- a/tests/Weew/ErrorHandler/ErrorHandlerTest.php +++ b/tests/Weew/ErrorHandler/ErrorHandlerTest.php @@ -92,25 +92,36 @@ public function test_prepend_and_get_exception_handlers() $this->assertEmpty($handler->getExceptionHandlers()); - $handler->addExceptionHandler(new FakeExceptionHandler(1)); + $handler->addExceptionHandler(FakeExceptionHandler::make(1)); + $handler->addExceptionHandler(FakeExceptionHandler::make(2)); + $handler->addExceptionHandler(FakeExceptionHandler::make(3)); - $this->assertCount(1, $handler->getExceptionHandlers()); + $this->assertOrder($handler, [1, 2, 3], 'Die ersten drei werden normal hinzugefügt'); - $handler->addExceptionHandler(new FakeExceptionHandler(2)); - $this->assertCount(2, $handler->getExceptionHandlers()); - $handler->addExceptionHandler(new FakeExceptionHandler(3)); - $this->assertCount(3, $handler->getExceptionHandlers()); -// $this->assertOrder($handler, [1, 2, 3], 'Die ersten drei werden normal hinzugefügt'); - - - - - $handler->prependExceptionHandler(new FakeExceptionHandler(42)); + $handler->prependExceptionHandler(FakeExceptionHandler::make(42)); $this->assertCount(4, $handler->getExceptionHandlers()); $this->assertOrder($handler, [42, 1, 2, 3], '42 sollte jetzt am Anfang sein'); - $handler->prependExceptionHandler(new FakeExceptionHandler(199)); + + $handler->prependExceptionHandler(FakeExceptionHandler::make(199)); $this->assertCount(5, $handler->getExceptionHandlers()); $this->assertOrder($handler, [199, 42, 1, 2, 3], '199 sollte jetzt am Anfang sein'); + + $handler->addExceptionHandler(FakeExceptionHandler::make(4)); + $this->assertCount(5, $handler->getExceptionHandlers()); + $this->assertOrder($handler, [199, 42, 1, 2, 3, 4], 'Man kann auch weiterhin welche anhängen'); + } + + public function test_prepend_works_on_empty() + { + $handler = new ErrorHandler(); + $this->assertEmpty($handler->getExceptionHandlers()); + + $handler->prependExceptionHandler(FakeExceptionHandler::make(1)); + $handler->prependExceptionHandler(FakeExceptionHandler::make(2)); + $handler->prependExceptionHandler(FakeExceptionHandler::make(3)); + + $this->assertOrder($handler, [3, 2, 1]); + } @@ -395,11 +406,6 @@ public function test_exception_from_recoverable_error_handler_is_handled() } } - /** - * @param ErrorHandler $handler - * @param array $expectedOrder - * @return void - */ private function assertOrder(ErrorHandler $handler, array $expectedOrder, string $message = '') { $ids = array_map(function (FakeExceptionHandler $fh) { diff --git a/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php b/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php index 76f938d..d6ff063 100644 --- a/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php +++ b/tests/Weew/ErrorHandler/Stubs/FakeExceptionHandler.php @@ -8,6 +8,14 @@ class FakeExceptionHandler implements IExceptionHandler { public $id; + /** + * @return int|mixed + */ + public static function make(int $id): self + { + return new self($id); + } + public function __construct($id = 1) { $this->id = $id; From 86df04c29ff37062ce60baab899ee8dab0f24057 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Fri, 12 Nov 2021 18:14:20 +0100 Subject: [PATCH 4/5] added to interface --- src/Weew/ErrorHandler/IErrorHandler.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Weew/ErrorHandler/IErrorHandler.php b/src/Weew/ErrorHandler/IErrorHandler.php index e1cbef1..9bacfcf 100644 --- a/src/Weew/ErrorHandler/IErrorHandler.php +++ b/src/Weew/ErrorHandler/IErrorHandler.php @@ -66,6 +66,13 @@ function isConvertingErrorsToExceptions(); */ function addExceptionHandler($handler); + /** + * Prepend an error handler for exceptions. + * + * @param callable|IExceptionHandler $handler + */ + function prependExceptionHandler($handler); + /** * Add an error handler for all kinds of native PHP errors. * From 160dea95aff51b48334d72b496b8eae23e688344 Mon Sep 17 00:00:00 2001 From: Philipp Kretzschmar Date: Fri, 12 Nov 2021 18:20:17 +0100 Subject: [PATCH 5/5] wupps --- tests/Weew/ErrorHandler/ErrorHandlerTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Weew/ErrorHandler/ErrorHandlerTest.php b/tests/Weew/ErrorHandler/ErrorHandlerTest.php index 7270b17..7a959d3 100644 --- a/tests/Weew/ErrorHandler/ErrorHandlerTest.php +++ b/tests/Weew/ErrorHandler/ErrorHandlerTest.php @@ -99,7 +99,6 @@ public function test_prepend_and_get_exception_handlers() $this->assertOrder($handler, [1, 2, 3], 'Die ersten drei werden normal hinzugefügt'); $handler->prependExceptionHandler(FakeExceptionHandler::make(42)); - $this->assertCount(4, $handler->getExceptionHandlers()); $this->assertOrder($handler, [42, 1, 2, 3], '42 sollte jetzt am Anfang sein'); $handler->prependExceptionHandler(FakeExceptionHandler::make(199)); @@ -107,7 +106,6 @@ public function test_prepend_and_get_exception_handlers() $this->assertOrder($handler, [199, 42, 1, 2, 3], '199 sollte jetzt am Anfang sein'); $handler->addExceptionHandler(FakeExceptionHandler::make(4)); - $this->assertCount(5, $handler->getExceptionHandlers()); $this->assertOrder($handler, [199, 42, 1, 2, 3, 4], 'Man kann auch weiterhin welche anhängen'); }