1717use Symfony \Component \Debug \Exception \FatalErrorException ;
1818use Symfony \Component \Debug \Exception \FatalThrowableError ;
1919use Symfony \Component \Debug \Exception \OutOfMemoryException ;
20+ use Symfony \Component \Debug \Exception \SilencedErrorContext ;
2021use Symfony \Component \Debug \FatalErrorHandler \UndefinedFunctionFatalErrorHandler ;
2122use Symfony \Component \Debug \FatalErrorHandler \UndefinedMethodFatalErrorHandler ;
2223use Symfony \Component \Debug \FatalErrorHandler \ClassNotFoundFatalErrorHandler ;
4344 * can see them and weight them as more important to fix than others of the same level.
4445 *
4546 * @author Nicolas Grekas <p@tchwork.com>
47+ * @author Grégoire Pineau <lyrixx@lyrixx.info>
4648 */
4749class ErrorHandler
4850{
@@ -88,7 +90,6 @@ class ErrorHandler
8890 private $ screamedErrors = 0x55 ; // E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE
8991 private $ loggedErrors = 0 ;
9092
91- private $ loggedTraces = array ();
9293 private $ isRecursive = 0 ;
9394 private $ isRoot = false ;
9495 private $ exceptionHandler ;
@@ -221,7 +222,7 @@ public function setLoggers(array $loggers)
221222
222223 if ($ flush ) {
223224 foreach ($ this ->bootstrappingLogger ->cleanLogs () as $ log ) {
224- $ type = $ log [2 ]['type ' ] ;
225+ $ type = $ log [2 ]['exception ' ]-> getSeverity () ;
225226 if (!isset ($ flush [$ type ])) {
226227 $ this ->bootstrappingLogger ->log ($ log [0 ], $ log [1 ], $ log [2 ]);
227228 } elseif ($ this ->loggers [$ type ][0 ]) {
@@ -361,6 +362,8 @@ private function reRegister($prev)
361362 */
362363 public function handleError ($ type , $ message , $ file , $ line , array $ context , array $ backtrace = null )
363364 {
365+ // Level is the current error reporting level to manage silent error.
366+ // Strong errors are not authorized to be silenced.
364367 $ level = error_reporting () | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED ;
365368 $ log = $ this ->loggedErrors & $ type ;
366369 $ throw = $ this ->thrownErrors & $ type & $ level ;
@@ -373,24 +376,28 @@ public function handleError($type, $message, $file, $line, array $context, array
373376 if (null !== $ backtrace && $ type & E_ERROR ) {
374377 // E_ERROR fatal errors are triggered on HHVM when
375378 // hhvm.error_handling.call_user_handler_on_fatals=1
376- // which is the way to get their backtrace .
379+ // which is the way to get their backtraces .
377380 $ this ->handleFatalError (compact ('type ' , 'message ' , 'file ' , 'line ' , 'backtrace ' ));
378381
379382 return true ;
380383 }
381384
382- if ($ throw ) {
383- if (null !== self ::$ toStringException ) {
384- $ throw = self ::$ toStringException ;
385- self ::$ toStringException = null ;
386- } elseif (($ this ->scopedErrors & $ type ) && class_exists (ContextErrorException::class)) {
387- $ throw = new ContextErrorException ($ this ->levels [$ type ].': ' .$ message , 0 , $ type , $ file , $ line , $ context );
388- } else {
389- $ throw = new \ErrorException ($ this ->levels [$ type ].': ' .$ message , 0 , $ type , $ file , $ line );
390- }
385+ $ logMessage = $ this ->levels [$ type ].': ' .$ message ;
386+
387+ if (null !== self ::$ toStringException ) {
388+ $ errorAsException = self ::$ toStringException ;
389+ self ::$ toStringException = null ;
390+ } elseif (!$ throw && !($ type & $ level )) {
391+ $ errorAsException = new SilencedErrorContext ($ type , $ file , $ line );
392+ } elseif ($ this ->scopedErrors & $ type ) {
393+ $ errorAsException = new ContextErrorException ($ logMessage , 0 , $ type , $ file , $ line , $ context );
394+ } else {
395+ $ errorAsException = new \ErrorException ($ logMessage , 0 , $ type , $ file , $ line );
396+ }
391397
398+ if ($ throw ) {
392399 if (E_USER_ERROR & $ type ) {
393- $ backtrace = $ backtrace ?: $ throw ->getTrace ();
400+ $ backtrace = $ backtrace ?: $ errorAsException ->getTrace ();
394401
395402 for ($ i = 1 ; isset ($ backtrace [$ i ]); ++$ i ) {
396403 if (isset ($ backtrace [$ i ]['function ' ], $ backtrace [$ i ]['type ' ], $ backtrace [$ i - 1 ]['function ' ])
@@ -410,7 +417,7 @@ public function handleError($type, $message, $file, $line, array $context, array
410417 if (($ e instanceof \Exception || $ e instanceof \Throwable) && $ e ->__toString () === $ message ) {
411418 if (1 === $ i ) {
412419 // On HHVM
413- $ throw = $ e ;
420+ $ errorAsException = $ e ;
414421 break ;
415422 }
416423 self ::$ toStringException = $ e ;
@@ -421,7 +428,7 @@ public function handleError($type, $message, $file, $line, array $context, array
421428
422429 if (1 < $ i ) {
423430 // On PHP (not on HHVM), display the original error message instead of the default one.
424- $ this ->handleException ($ throw );
431+ $ this ->handleException ($ errorAsException );
425432
426433 // Stop the process by giving back the error to the native handler.
427434 return false ;
@@ -430,47 +437,23 @@ public function handleError($type, $message, $file, $line, array $context, array
430437 }
431438 }
432439
433- throw $ throw ;
434- }
435-
436- // For duplicated errors, log the trace only once
437- $ e = md5 ("{$ type }/ {$ line }/ {$ file }\x00{$ message }" , true );
438- $ trace = true ;
439-
440- if (!($ this ->tracedErrors & $ type ) || isset ($ this ->loggedTraces [$ e ])) {
441- $ trace = false ;
442- } else {
443- $ this ->loggedTraces [$ e ] = 1 ;
444- }
445-
446- $ e = compact ('type ' , 'file ' , 'line ' , 'level ' );
447-
448- if ($ type & $ level ) {
449- if ($ this ->scopedErrors & $ type ) {
450- $ e ['scope_vars ' ] = $ context ;
451- if ($ trace ) {
452- $ e ['stack ' ] = $ backtrace ?: debug_backtrace (DEBUG_BACKTRACE_PROVIDE_OBJECT );
453- }
454- } elseif ($ trace ) {
455- if (null === $ backtrace ) {
456- $ e ['stack ' ] = debug_backtrace (DEBUG_BACKTRACE_IGNORE_ARGS );
457- } else {
458- foreach ($ backtrace as &$ frame ) {
459- unset($ frame ['args ' ], $ frame );
460- }
461- $ e ['stack ' ] = $ backtrace ;
462- }
463- }
440+ throw $ errorAsException ;
464441 }
465442
466443 if ($ this ->isRecursive ) {
467444 $ log = 0 ;
468445 } elseif (self ::$ stackedErrorLevels ) {
469- self ::$ stackedErrors [] = array ($ this ->loggers [$ type ][0 ], ($ type & $ level ) ? $ this ->loggers [$ type ][1 ] : LogLevel::DEBUG , $ message , $ e );
446+ self ::$ stackedErrors [] = array (
447+ $ this ->loggers [$ type ][0 ],
448+ ($ type & $ level ) ? $ this ->loggers [$ type ][1 ] : LogLevel::DEBUG ,
449+ $ logMessage ,
450+ array ('exception ' => $ errorAsException ),
451+ );
470452 } else {
471453 try {
472454 $ this ->isRecursive = true ;
473- $ this ->loggers [$ type ][0 ]->log (($ type & $ level ) ? $ this ->loggers [$ type ][1 ] : LogLevel::DEBUG , $ message , $ e );
455+ $ level = ($ type & $ level ) ? $ this ->loggers [$ type ][1 ] : LogLevel::DEBUG ;
456+ $ this ->loggers [$ type ][0 ]->log ($ level , $ logMessage , array ('exception ' => $ errorAsException ));
474457 } finally {
475458 $ this ->isRecursive = false ;
476459 }
@@ -495,20 +478,13 @@ public function handleException($exception, array $error = null)
495478 $ type = $ exception instanceof FatalErrorException ? $ exception ->getSeverity () : E_ERROR ;
496479
497480 if (($ this ->loggedErrors & $ type ) || $ exception instanceof FatalThrowableError) {
498- $ e = array (
499- 'type ' => $ type ,
500- 'file ' => $ exception ->getFile (),
501- 'line ' => $ exception ->getLine (),
502- 'level ' => error_reporting (),
503- 'stack ' => $ exception ->getTrace (),
504- );
505481 if ($ exception instanceof FatalErrorException) {
506482 if ($ exception instanceof FatalThrowableError) {
507483 $ error = array (
508484 'type ' => $ type ,
509485 'message ' => $ message = $ exception ->getMessage (),
510- 'file ' => $ e [ ' file ' ] ,
511- 'line ' => $ e [ ' line ' ] ,
486+ 'file ' => $ exception -> getFile () ,
487+ 'line ' => $ exception -> getLine () ,
512488 );
513489 } else {
514490 $ message = 'Fatal ' .$ exception ->getMessage ();
@@ -523,7 +499,7 @@ public function handleException($exception, array $error = null)
523499 }
524500 }
525501 if ($ this ->loggedErrors & $ type ) {
526- $ this ->loggers [$ type ][0 ]->log ($ this ->loggers [$ type ][1 ], $ message , $ e );
502+ $ this ->loggers [$ type ][0 ]->log ($ this ->loggers [$ type ][1 ], $ message , array ( ' exception ' => $ exception ) );
527503 }
528504 if ($ exception instanceof FatalErrorException && !$ exception instanceof OutOfMemoryException && $ error ) {
529505 foreach ($ this ->getFatalErrorHandlers () as $ handler ) {
@@ -629,19 +605,19 @@ public static function unstackErrors()
629605 $ level = array_pop (self ::$ stackedErrorLevels );
630606
631607 if (null !== $ level ) {
632- $ e = error_reporting ($ level );
633- if ($ e !== ($ level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR )) {
608+ $ errorReportingLevel = error_reporting ($ level );
609+ if ($ errorReportingLevel !== ($ level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR )) {
634610 // If the user changed the error level, do not overwrite it
635- error_reporting ($ e );
611+ error_reporting ($ errorReportingLevel );
636612 }
637613 }
638614
639615 if (empty (self ::$ stackedErrorLevels )) {
640616 $ errors = self ::$ stackedErrors ;
641617 self ::$ stackedErrors = array ();
642618
643- foreach ($ errors as $ e ) {
644- $ e [0 ]->log ($ e [1 ], $ e [2 ], $ e [3 ]);
619+ foreach ($ errors as $ error ) {
620+ $ error [0 ]->log ($ error [1 ], $ error [2 ], $ error [3 ]);
645621 }
646622 }
647623 }
0 commit comments