Skip to content

Commit

Permalink
Fix #122: Do exit(1) after all shutdown functions, even postponed ones (
Browse files Browse the repository at this point in the history
  • Loading branch information
samdark authored Jul 11, 2024
1 parent ee21ea1 commit 3931824
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Enh #114: Show full argument by click (@xepozz)
- Enh #113: Simplify error log (@xepozz)
- Enh #112: Add copy cURL button, sort request headers, fix UI (@xepozz)
- Bug #122: Do `exit(1)` after all shutdown functions, even postponed ones (@samdark)

## 3.2.1 March 07, 2024

Expand Down
44 changes: 38 additions & 6 deletions src/ErrorHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,17 @@ final class ErrorHandler
private bool $enabled = false;
private bool $initialized = false;

/**
* @param LoggerInterface $logger Logger to write errors to.
* @param ThrowableRendererInterface $defaultRenderer Default throwable renderer.
* @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events.
* @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last.
*/
public function __construct(
private LoggerInterface $logger,
private ThrowableRendererInterface $defaultRenderer,
private ?EventDispatcherInterface $eventDispatcher = null,
private int $exitShutdownHandlerDepth = 2

Check warning on line 54 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "DecrementInteger": --- Original +++ New @@ @@ * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ - public function __construct(private LoggerInterface $logger, private ThrowableRendererInterface $defaultRenderer, private ?EventDispatcherInterface $eventDispatcher = null, private int $exitShutdownHandlerDepth = 2) + public function __construct(private LoggerInterface $logger, private ThrowableRendererInterface $defaultRenderer, private ?EventDispatcherInterface $eventDispatcher = null, private int $exitShutdownHandlerDepth = 1) { } /**

Check warning on line 54 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "IncrementInteger": --- Original +++ New @@ @@ * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher for error events. * @param int $exitShutdownHandlerDepth Depth of the exit() shutdown handler to ensure it's executed last. */ - public function __construct(private LoggerInterface $logger, private ThrowableRendererInterface $defaultRenderer, private ?EventDispatcherInterface $eventDispatcher = null, private int $exitShutdownHandlerDepth = 2) + public function __construct(private LoggerInterface $logger, private ThrowableRendererInterface $defaultRenderer, private ?EventDispatcherInterface $eventDispatcher = null, private int $exitShutdownHandlerDepth = 3) { } /**
) {
}

Expand Down Expand Up @@ -108,7 +115,7 @@ public function register(): void

$this->initializeOnce();

Check warning on line 116 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "MethodCallRemoval": --- Original +++ New @@ @@ if ($this->memoryReserveSize > 0) { $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } - $this->initializeOnce(); + // Handles throwable that isn't caught otherwise, echo output and exit. set_exception_handler(function (Throwable $t) : void { if (!$this->enabled) {

// Handles throwable, echo output and exit.
// Handles throwable that isn't caught otherwise, echo output and exit.
set_exception_handler(function (Throwable $t): void {

Check warning on line 119 in src/ErrorHandler.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.1-ubuntu-latest

Escaped Mutant for Mutator "FunctionCallRemoval": --- Original +++ New @@ @@ $this->memoryReserve = str_repeat('x', $this->memoryReserveSize); } $this->initializeOnce(); - // Handles throwable that isn't caught otherwise, echo output and exit. - set_exception_handler(function (Throwable $t) : void { - if (!$this->enabled) { - return; - } - $this->renderThrowableAndTerminate($t); - }); + // Handles PHP execution errors such as warnings and notices. set_error_handler(function (int $severity, string $message, string $file, int $line) : bool { if (!$this->enabled) {
if (!$this->enabled) {
return;
Expand Down Expand Up @@ -199,16 +206,41 @@ private function renderThrowableAndTerminate(Throwable $t): void
if (!empty($this->workingDirectory)) {
chdir($this->workingDirectory);
}
// disable error capturing to avoid recursive errors while handling exceptions
// Disable error capturing to avoid recursive errors while handling exceptions.
$this->unregister();
// set preventive HTTP status code to 500 in case error handling somehow fails and headers are sent
// Set preventive HTTP status code to 500 in case error handling somehow fails and headers are sent.
http_response_code(Status::INTERNAL_SERVER_ERROR);

echo $this->handle($t);
$this->eventDispatcher?->dispatch(new ApplicationError($t));

register_shutdown_function(static function (): void {
exit(1);
});
$handler = $this->wrapShutdownHandler(
static function (): void {
exit(1);
},
$this->exitShutdownHandlerDepth
);

register_shutdown_function($handler);
}

/**
* Wraps shutdown handler into another shutdown handler to ensure it is called last after all other shutdown
* functions, even those added to the end.
*
* @param callable $handler Shutdown handler to wrap.
* @param int $depth Wrapping depth.
* @return callable Wrapped handler.
*/
private function wrapShutdownHandler(callable $handler, int $depth): callable
{
$currentDepth = 0;
while ($currentDepth < $depth) {
$handler = static function() use ($handler): void {
register_shutdown_function($handler);
};
$currentDepth++;
}
return $handler;
}
}

0 comments on commit 3931824

Please sign in to comment.