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
8890private $ screamedErrors =0x55 ;// E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE
8991private $ loggedErrors =0 ;
9092
91- private $ loggedTraces =array ();
9293private $ isRecursive =0 ;
9394private $ isRoot =false ;
9495private $ exceptionHandler ;
@@ -221,7 +222,7 @@ public function setLoggers(array $loggers)
221222
222223if ($ flush ) {
223224foreach ($ this ->bootstrappingLogger ->cleanLogs ()as $ log ) {
224- $ type =$ log [2 ]['type ' ] ;
225+ $ type =$ log [2 ]['exception ' ]-> getSeverity () ;
225226if (!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 */
362363public 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
373376if (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 theirbacktrace .
379+ // which is the way to get theirbacktraces .
377380$ this ->handleFatalError (compact ('type ' ,'message ' ,'file ' ,'line ' ,'backtrace ' ));
378381
379382return 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 ) {
392399if (E_USER_ERROR &$ type ) {
393- $ backtrace =$ backtrace ?:$ throw ->getTrace ();
400+ $ backtrace =$ backtrace ?:$ errorAsException ->getTrace ();
394401
395402for ($ i =1 ;isset ($ backtrace [$ i ]); ++$ i ) {
396403if (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
410417if (($ einstanceof \Exception ||$ einstanceof \Throwable) &&$ e ->__toString () ===$ message ) {
411418if (1 ===$ i ) {
412419// On HHVM
413- $ throw =$ e ;
420+ $ errorAsException =$ e ;
414421break ;
415422 }
416423self ::$ toStringException =$ e ;
@@ -421,7 +428,7 @@ public function handleError($type, $message, $file, $line, array $context, array
421428
422429if (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.
427434return 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 ($ backtraceas &$ frame ) {
459- unset($ frame ['args ' ],$ frame );
460- }
461- $ e ['stack ' ] =$ backtrace ;
462- }
463- }
440+ throw $ errorAsException ;
464441 }
465442
466443if ($ 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 {
471453try {
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 =$ exceptioninstanceof FatalErrorException ?$ exception ->getSeverity () :E_ERROR ;
496479
497480if (($ this ->loggedErrors &$ type ) ||$ exceptioninstanceof FatalThrowableError) {
498- $ e =array (
499- 'type ' =>$ type ,
500- 'file ' =>$ exception ->getFile (),
501- 'line ' =>$ exception ->getLine (),
502- 'level ' =>error_reporting (),
503- 'stack ' =>$ exception ->getTrace (),
504- );
505481if ($ exceptioninstanceof FatalErrorException) {
506482if ($ exceptioninstanceof 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 }
525501if ($ 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 }
528504if ($ exceptioninstanceof FatalErrorException && !$ exceptioninstanceof OutOfMemoryException &&$ error ) {
529505foreach ($ this ->getFatalErrorHandlers ()as $ handler ) {
@@ -629,19 +605,19 @@ public static function unstackErrors()
629605$ level =array_pop (self ::$ stackedErrorLevels );
630606
631607if (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
639615if (empty (self ::$ stackedErrorLevels )) {
640616$ errors =self ::$ stackedErrors ;
641617self ::$ stackedErrors =array ();
642618
643- foreach ($ errorsas $ e ) {
644- $ e [0 ]->log ($ e [1 ],$ e [2 ],$ e [3 ]);
619+ foreach ($ errorsas $ error ) {
620+ $ error [0 ]->log ($ error [1 ],$ error [2 ],$ error [3 ]);
645621 }
646622 }
647623 }