Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
exceptionhandler.php
1<?php
2
3namespace Bitrix\Main\Diag;
4
6{
7 private $debug = false;
8 private $handledErrorsTypes;
9 private $exceptionErrorsTypes;
10 private array $trackModules = [];
11 private $catchOverflowMemory = false;
12 private $memoryReserveLimit = 65536;
14 private $memoryReserve;
15 private $ignoreSilence = false;
16 private $assertionThrowsException = true;
17 private $assertionErrorType = E_USER_ERROR;
19 private $handlerLog = null;
20 private $handlerLogCreator = null;
22 private $handlerOutput = null;
23 private $handlerOutputCreator = null;
24 private $isInitialized = false;
25
29 public function __construct()
30 {
31 $this->handledErrorsTypes = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
32 $this->exceptionErrorsTypes = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
33 }
34
43 public function setDebugMode($debug)
44 {
45 $this->debug = $debug;
46 }
47
55 public function setOverflowMemoryCatching($catchOverflowMemory)
56 {
57 $this->catchOverflowMemory = $catchOverflowMemory;
58 }
59
68 public function setHandledErrorsTypes($handledErrorsTypes)
69 {
70 $this->handledErrorsTypes = $handledErrorsTypes;
71 }
72
73 public function getTrackModules(): array
74 {
75 return $this->trackModules;
76 }
77
78 public function setTrackModules(array $trackModules): void
79 {
80 $this->trackModules = $trackModules;
81 }
82
91 public function setAssertionErrorType($assertionErrorType)
92 {
93 $this->assertionErrorType = $assertionErrorType;
94 }
95
103 public function setAssertionThrowsException($assertionThrowsException)
104 {
105 $this->assertionThrowsException = $assertionThrowsException;
106 }
107
116 public function setExceptionErrorsTypes($errorTypesException)
117 {
118 $this->exceptionErrorsTypes = $errorTypesException;
119 }
120
128 public function setIgnoreSilence($ignoreSilence)
129 {
130 $this->ignoreSilence = $ignoreSilence;
131 }
132
140 public function setHandlerLog(ExceptionHandlerLog $handlerLog = null)
141 {
142 $this->handlerLog = $handlerLog;
143 }
144
152 public function setHandlerOutput(IExceptionHandlerOutput $handlerOutput)
153 {
154 $this->handlerOutput = $handlerOutput;
155 }
156
162 protected function initializeEnvironment()
163 {
164 if ($this->debug)
165 {
166 error_reporting($this->handledErrorsTypes);
167 @ini_set('display_errors', 'On');
168 @ini_set('display_startup_errors', 'On');
169 @ini_set('report_memleaks', 'On');
170 }
171 else
172 {
173 error_reporting(E_ERROR | E_PARSE);
174 }
175 }
176
182 protected function getHandlerOutput()
183 {
184 if ($this->handlerOutput === null)
185 {
186 $h = $this->handlerOutputCreator;
187 if (is_callable($h))
188 {
189 $this->handlerOutput = call_user_func_array($h, []);
190 }
191 }
192
193 return $this->handlerOutput;
194 }
195
201 protected function getHandlerLog()
202 {
203 if ($this->handlerLog === null)
204 {
205 $h = $this->handlerLogCreator;
206 if (is_callable($h))
207 {
208 $this->handlerLog = call_user_func_array($h, []);
209 }
210 }
211
212 return $this->handlerLog;
213 }
214
224 public function initialize($exceptionHandlerOutputCreator, $exceptionHandlerLogCreator = null)
225 {
226 if ($this->isInitialized)
227 {
228 return;
229 }
230
231 $this->initializeEnvironment();
232
233 $this->handlerOutputCreator = $exceptionHandlerOutputCreator;
234 $this->handlerLogCreator = $exceptionHandlerLogCreator;
235
236 if ($this->catchOverflowMemory)
237 {
238 $this->memoryReserve = str_repeat('b', $this->memoryReserveLimit);
239 }
240
241 set_error_handler([$this, "handleError"], $this->handledErrorsTypes);
242 set_exception_handler([$this, "handleException"]);
243 register_shutdown_function([$this, "handleFatalError"]);
244
245 if ($this->debug)
246 {
247 assert_options(ASSERT_ACTIVE, 1);
248 assert_options(ASSERT_WARNING, 0);
249 assert_options(ASSERT_BAIL, 0);
250 assert_options(ASSERT_CALLBACK, [$this, "handleAssertion"]);
251 }
252 else
253 {
254 assert_options(ASSERT_ACTIVE, 0);
255 }
256
257 $this->isInitialized = true;
258 }
259
270 public function handleException($exception, $logType = ExceptionHandlerLog::UNCAUGHT_EXCEPTION)
271 {
272 $this->writeToLog($exception, $logType);
273 $out = $this->getHandlerOutput();
274 $out->renderExceptionMessage($exception, $this->debug);
275 die();
276 }
277
291 public function handleError($code, $message, $file, $line)
292 {
293 $exception = new \ErrorException($message, 0, $code, $file, $line);
294
295 if (!$this->ignoreSilence)
296 {
297 $errorReporting = error_reporting();
298 if (
299 $errorReporting === 0 //Prior to PHP 8.0.0
300 || $errorReporting === (E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR | E_PARSE)
301 )
302 {
303 return true;
304 }
305 }
306
307 if (!$this->isFileInTrackedModules($file))
308 {
309 return true;
310 }
311
312 if ($code & $this->exceptionErrorsTypes)
313 {
314 throw $exception;
315 }
316 else
317 {
319 return true;
320 }
321 }
322
323 private function isFileInTrackedModules(string $file): bool
324 {
325 $modules = $this->getTrackModules();
326 if (!$modules)
327 {
328 return true;
329 }
330
331 foreach ($modules as $module)
332 {
333 $moduleDir = DIRECTORY_SEPARATOR . "modules" . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR;
334 if (str_contains($file, $moduleDir))
335 {
336 return true;
337 }
338 }
339
340 return false;
341 }
342
355 public function handleAssertion($file, $line, $message)
356 {
357 $exception = new \ErrorException($message, 0, $this->assertionErrorType, $file, $line);
358
359 if ($this->assertionThrowsException)
360 {
361 throw $exception;
362 }
363 else
364 {
365 $this->writeToLog($exception, ExceptionHandlerLog::ASSERTION);
366 }
367 }
368
377 public function handleFatalError()
378 {
379 $this->memoryReserve = null;
380 if ($error = error_get_last())
381 {
382 if (($error['type'] & (E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR)))
383 {
384 if (($error['type'] & $this->handledErrorsTypes))
385 {
386 $exception = new \ErrorException($error['message'], 0, $error['type'], $error['file'], $error['line']);
388 }
389 }
390 }
391 }
392
402 public function writeToLog($exception, $logType = null)
403 {
404 $log = $this->getHandlerLog();
405 $log?->write($exception, $logType);
406 }
407}
handleError($code, $message, $file, $line)
setOverflowMemoryCatching($catchOverflowMemory)
setHandledErrorsTypes($handledErrorsTypes)
setExceptionErrorsTypes($errorTypesException)
setHandlerLog(ExceptionHandlerLog $handlerLog=null)
writeToLog($exception, $logType=null)
setAssertionThrowsException($assertionThrowsException)
initialize($exceptionHandlerOutputCreator, $exceptionHandlerLogCreator=null)
handleException($exception, $logType=ExceptionHandlerLog::UNCAUGHT_EXCEPTION)
setHandlerOutput(IExceptionHandlerOutput $handlerOutput)
handleAssertion($file, $line, $message)
setAssertionErrorType($assertionErrorType)