Skip to content

Commit 1a71a8a

Browse files
vjiksamdark
andauthored
Fix duplicate registration handlers (#70)
Co-authored-by: Alexander Makarov <[email protected]>
1 parent 0b616a9 commit 1a71a8a

File tree

2 files changed

+62
-27
lines changed

2 files changed

+62
-27
lines changed

CHANGELOG.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22

33
## 2.1.1 under development
44

5-
- no changes in this release.
5+
- Bug #70: Prevent duplication of throwable rendering (@vjik)
66

77
## 2.1.0 June 15, 2022
88

9-
- Enh #54: Add shutdown event, fix cwd (rustamwin)
10-
- Enh #55: Defer exit on terminate (rustamwin)
11-
- Enh #57: Add markdown support for friendly exception solutions (vjik)
12-
- Enh #58: Add support for `2.0`, `3.0` versions of `psr/log` (rustamwin)
9+
- Enh #54: Add shutdown event, fix cwd (@rustamwin)
10+
- Enh #55: Defer exit on terminate (@rustamwin)
11+
- Enh #57: Add markdown support for friendly exception solutions (@vjik)
12+
- Enh #58: Add support for `2.0`, `3.0` versions of `psr/log` (@rustamwin)
1313

1414
## 2.0.2 February 04, 2022
1515

16-
- Bug #50: Fix JSON rendering on JSON recursion exception (thenotsoft)
16+
- Bug #50: Fix JSON rendering on JSON recursion exception (@thenotsoft)
1717

1818
## 2.0.1 January 26, 2022
1919

20-
- Bug #49: Fix JSON rendering of non-UTF-8 encoded string (devanych)
20+
- Bug #49: Fix JSON rendering of non-UTF-8 encoded string (@devanych)
2121

2222
## 2.0.0 November 09, 2021
2323

24-
- Chg #48: Transfer `HeaderHelper` to `yiisoft/http` package (devanych)
25-
- Enh #45: Improve appearance of solution from friendly exceptions (vjik)
24+
- Chg #48: Transfer `HeaderHelper` to `yiisoft/http` package (@devanych)
25+
- Enh #45: Improve appearance of solution from friendly exceptions (@vjik)
2626

2727
## 1.0.0 May 13, 2021
2828

src/ErrorHandler.php

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,12 @@
1919
use function ini_set;
2020
use function http_response_code;
2121
use function register_shutdown_function;
22-
use function restore_error_handler;
23-
use function restore_exception_handler;
2422
use function set_error_handler;
2523
use function set_exception_handler;
2624
use function str_repeat;
2725

2826
/**
29-
* ErrorHandler handles out of memory errors, fatals, warnings, notices and exceptions.
27+
* `ErrorHandler` handles out of memory errors, fatals, warnings, notices and exceptions.
3028
*/
3129
final class ErrorHandler
3230
{
@@ -40,6 +38,8 @@ final class ErrorHandler
4038
private string $memoryReserve = '';
4139
private bool $debug = false;
4240
private ?string $workingDirectory = null;
41+
private bool $enabled = false;
42+
private bool $initialized = false;
4343

4444
private LoggerInterface $logger;
4545
private ThrowableRendererInterface $defaultRenderer;
@@ -106,22 +106,35 @@ public function memoryReserveSize(int $size): void
106106
}
107107

108108
/**
109-
* Register this error handler.
109+
* Register PHP exception and error handlers and enable this error handler.
110110
*/
111111
public function register(): void
112112
{
113-
// Disables the display of error.
114-
if (function_exists('ini_set')) {
115-
ini_set('display_errors', '0');
113+
if ($this->enabled) {
114+
return;
115+
}
116+
117+
if ($this->memoryReserveSize > 0) {
118+
$this->memoryReserve = str_repeat('x', $this->memoryReserveSize);
116119
}
117120

121+
$this->initializeOnce();
122+
118123
// Handles throwable, echo output and exit.
119124
set_exception_handler(function (Throwable $t): void {
125+
if (!$this->enabled) {
126+
return;
127+
}
128+
120129
$this->renderThrowableAndTerminate($t);
121130
});
122131

123132
// Handles PHP execution errors such as warnings and notices.
124-
set_error_handler(static function (int $severity, string $message, string $file, int $line): bool {
133+
set_error_handler(function (int $severity, string $message, string $file, int $line): bool {
134+
if (!$this->enabled) {
135+
return false;
136+
}
137+
125138
if (!(error_reporting() & $severity)) {
126139
// This error code is not included in error_reporting.
127140
return true;
@@ -130,12 +143,40 @@ public function register(): void
130143
throw new ErrorException($message, $severity, $severity, $file, $line);
131144
});
132145

133-
if ($this->memoryReserveSize > 0) {
134-
$this->memoryReserve = str_repeat('x', $this->memoryReserveSize);
146+
$this->enabled = true;
147+
}
148+
149+
/**
150+
* Disable this error handler.
151+
*/
152+
public function unregister(): void
153+
{
154+
if (!$this->enabled) {
155+
return;
156+
}
157+
158+
$this->memoryReserve = '';
159+
160+
$this->enabled = false;
161+
}
162+
163+
private function initializeOnce(): void
164+
{
165+
if ($this->initialized) {
166+
return;
167+
}
168+
169+
// Disables the display of error.
170+
if (function_exists('ini_set')) {
171+
ini_set('display_errors', '0');
135172
}
136173

137174
// Handles fatal error.
138175
register_shutdown_function(function (): void {
176+
if (!$this->enabled) {
177+
return;
178+
}
179+
139180
$this->memoryReserve = '';
140181
$e = error_get_last();
141182

@@ -148,15 +189,8 @@ public function register(): void
148189
if (!(PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg')) {
149190
$this->workingDirectory = getcwd();
150191
}
151-
}
152192

153-
/**
154-
* Unregisters this error handler by restoring the PHP error and exception handlers.
155-
*/
156-
public function unregister(): void
157-
{
158-
restore_error_handler();
159-
restore_exception_handler();
193+
$this->initialized = true;
160194
}
161195

162196
/**
@@ -178,6 +212,7 @@ private function renderThrowableAndTerminate(Throwable $t): void
178212
if ($this->eventDispatcher !== null) {
179213
$this->eventDispatcher->dispatch(new ApplicationError($t));
180214
}
215+
181216
register_shutdown_function(static function (): void {
182217
exit(1);
183218
});

0 commit comments

Comments
 (0)