comparison vendor/symfony/debug/ErrorHandler.php @ 12:7a779792577d

Update Drupal core to v8.4.5 (via Composer)
author Chris Cannam
date Fri, 23 Feb 2018 15:52:07 +0000
parents 4c8ae668cc8c
children 5fb285c0d0e3
comparison
equal deleted inserted replaced
11:bfffd8d7479a 12:7a779792577d
98 98
99 private static $reservedMemory; 99 private static $reservedMemory;
100 private static $stackedErrors = array(); 100 private static $stackedErrors = array();
101 private static $stackedErrorLevels = array(); 101 private static $stackedErrorLevels = array();
102 private static $toStringException = null; 102 private static $toStringException = null;
103 private static $silencedErrorCache = array();
104 private static $silencedErrorCount = 0;
103 private static $exitCode = 0; 105 private static $exitCode = 0;
104 106
105 /** 107 /**
106 * Registers the error handler. 108 * Registers the error handler.
107 * 109 *
130 132
131 if ($handlerIsNew && is_array($prev) && $prev[0] instanceof self) { 133 if ($handlerIsNew && is_array($prev) && $prev[0] instanceof self) {
132 $handler = $prev[0]; 134 $handler = $prev[0];
133 $replace = false; 135 $replace = false;
134 } 136 }
135 if ($replace || !$prev) { 137 if (!$replace && $prev) {
136 $handler->setExceptionHandler(set_exception_handler(array($handler, 'handleException'))); 138 restore_error_handler();
139 }
140 if (is_array($prev = set_exception_handler(array($handler, 'handleException'))) && $prev[0] === $handler) {
141 restore_exception_handler();
137 } else { 142 } else {
138 restore_error_handler(); 143 $handler->setExceptionHandler($prev);
139 } 144 }
140 145
141 $handler->throwAt(E_ALL & $handler->thrownErrors, true); 146 $handler->throwAt(E_ALL & $handler->thrownErrors, true);
142 147
143 return $handler; 148 return $handler;
405 410
406 if (null !== self::$toStringException) { 411 if (null !== self::$toStringException) {
407 $errorAsException = self::$toStringException; 412 $errorAsException = self::$toStringException;
408 self::$toStringException = null; 413 self::$toStringException = null;
409 } elseif (!$throw && !($type & $level)) { 414 } elseif (!$throw && !($type & $level)) {
410 $errorAsException = new SilencedErrorContext($type, $file, $line); 415 if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) {
416 $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array();
417 $errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace);
418 } elseif (isset(self::$silencedErrorCache[$id][$message])) {
419 $lightTrace = null;
420 $errorAsException = self::$silencedErrorCache[$id][$message];
421 ++$errorAsException->count;
422 } else {
423 $lightTrace = array();
424 $errorAsException = null;
425 }
426
427 if (100 < ++self::$silencedErrorCount) {
428 self::$silencedErrorCache = $lightTrace = array();
429 self::$silencedErrorCount = 1;
430 }
431 if ($errorAsException) {
432 self::$silencedErrorCache[$id][$message] = $errorAsException;
433 }
434 if (null === $lightTrace) {
435 return;
436 }
411 } else { 437 } else {
412 if ($scope) { 438 if ($scope) {
413 $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context); 439 $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context);
414 } else { 440 } else {
415 $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); 441 $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
416 } 442 }
417 443
418 // Clean the trace by removing function arguments and the first frames added by the error handler itself. 444 // Clean the trace by removing function arguments and the first frames added by the error handler itself.
419 if ($throw || $this->tracedErrors & $type) { 445 if ($throw || $this->tracedErrors & $type) {
420 $backtrace = $backtrace ?: $errorAsException->getTrace(); 446 $backtrace = $backtrace ?: $errorAsException->getTrace();
421 $lightTrace = $backtrace; 447 $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw);
422
423 for ($i = 0; isset($backtrace[$i]); ++$i) {
424 if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
425 $lightTrace = array_slice($lightTrace, 1 + $i);
426 break;
427 }
428 }
429 if (!($throw || $this->scopedErrors & $type)) {
430 for ($i = 0; isset($lightTrace[$i]); ++$i) {
431 unset($lightTrace[$i]['args']);
432 }
433 }
434 $this->traceReflector->setValue($errorAsException, $lightTrace); 448 $this->traceReflector->setValue($errorAsException, $lightTrace);
435 } else { 449 } else {
436 $this->traceReflector->setValue($errorAsException, array()); 450 $this->traceReflector->setValue($errorAsException, array());
437 } 451 }
438 } 452 }
485 } elseif (self::$stackedErrorLevels) { 499 } elseif (self::$stackedErrorLevels) {
486 self::$stackedErrors[] = array( 500 self::$stackedErrors[] = array(
487 $this->loggers[$type][0], 501 $this->loggers[$type][0],
488 ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, 502 ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG,
489 $logMessage, 503 $logMessage,
490 array('exception' => $errorAsException), 504 $errorAsException ? array('exception' => $errorAsException) : array(),
491 ); 505 );
492 } else { 506 } else {
493 try { 507 try {
494 $this->isRecursive = true; 508 $this->isRecursive = true;
495 $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG; 509 $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG;
496 $this->loggers[$type][0]->log($level, $logMessage, array('exception' => $errorAsException)); 510 $this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? array('exception' => $errorAsException) : array());
497 } finally { 511 } finally {
498 $this->isRecursive = false; 512 $this->isRecursive = false;
499 } 513 }
500 } 514 }
501 515
517 } 531 }
518 if (!$exception instanceof \Exception) { 532 if (!$exception instanceof \Exception) {
519 $exception = new FatalThrowableError($exception); 533 $exception = new FatalThrowableError($exception);
520 } 534 }
521 $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR; 535 $type = $exception instanceof FatalErrorException ? $exception->getSeverity() : E_ERROR;
536 $handlerException = null;
522 537
523 if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) { 538 if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) {
524 if ($exception instanceof FatalErrorException) { 539 if ($exception instanceof FatalErrorException) {
525 if ($exception instanceof FatalThrowableError) { 540 if ($exception instanceof FatalThrowableError) {
526 $error = array( 541 $error = array(
532 } else { 547 } else {
533 $message = 'Fatal '.$exception->getMessage(); 548 $message = 'Fatal '.$exception->getMessage();
534 } 549 }
535 } elseif ($exception instanceof \ErrorException) { 550 } elseif ($exception instanceof \ErrorException) {
536 $message = 'Uncaught '.$exception->getMessage(); 551 $message = 'Uncaught '.$exception->getMessage();
537 if ($exception instanceof ContextErrorException) {
538 $e['context'] = $exception->getContext();
539 }
540 } else { 552 } else {
541 $message = 'Uncaught Exception: '.$exception->getMessage(); 553 $message = 'Uncaught Exception: '.$exception->getMessage();
542 } 554 }
543 } 555 }
544 if ($this->loggedErrors & $type) { 556 if ($this->loggedErrors & $type) {
554 $exception = $e; 566 $exception = $e;
555 break; 567 break;
556 } 568 }
557 } 569 }
558 } 570 }
559 if (empty($this->exceptionHandler)) {
560 throw $exception; // Give back $exception to the native handler
561 }
562 try { 571 try {
563 call_user_func($this->exceptionHandler, $exception); 572 if (null !== $this->exceptionHandler) {
573 return \call_user_func($this->exceptionHandler, $exception);
574 }
575 $handlerException = $handlerException ?: $exception;
564 } catch (\Exception $handlerException) { 576 } catch (\Exception $handlerException) {
565 } catch (\Throwable $handlerException) { 577 } catch (\Throwable $handlerException) {
566 } 578 }
567 if (isset($handlerException)) { 579 $this->exceptionHandler = null;
568 $this->exceptionHandler = null; 580 if ($exception === $handlerException) {
569 $this->handleException($handlerException); 581 self::$reservedMemory = null; // Disable the fatal error handler
570 } 582 throw $exception; // Give back $exception to the native handler
583 }
584 $this->handleException($handlerException);
571 } 585 }
572 586
573 /** 587 /**
574 * Shutdown registered function for handling PHP fatal errors. 588 * Shutdown registered function for handling PHP fatal errors.
575 * 589 *
581 { 595 {
582 if (null === self::$reservedMemory) { 596 if (null === self::$reservedMemory) {
583 return; 597 return;
584 } 598 }
585 599
586 self::$reservedMemory = null; 600 $handler = self::$reservedMemory = null;
587 601 $handlers = array();
588 $handler = set_error_handler('var_dump'); 602 $previousHandler = null;
589 $handler = is_array($handler) ? $handler[0] : null; 603 $sameHandlerLimit = 10;
590 restore_error_handler(); 604
591 605 while (!is_array($handler) || !$handler[0] instanceof self) {
592 if (!$handler instanceof self) { 606 $handler = set_exception_handler('var_dump');
607 restore_exception_handler();
608
609 if (!$handler) {
610 break;
611 }
612 restore_exception_handler();
613
614 if ($handler !== $previousHandler) {
615 array_unshift($handlers, $handler);
616 $previousHandler = $handler;
617 } elseif (0 === --$sameHandlerLimit) {
618 $handler = null;
619 break;
620 }
621 }
622 foreach ($handlers as $h) {
623 set_exception_handler($h);
624 }
625 if (!$handler) {
593 return; 626 return;
594 } 627 }
628 if ($handler !== $h) {
629 $handler[0]->setExceptionHandler($h);
630 }
631 $handler = $handler[0];
632 $handlers = array();
595 633
596 if ($exit = null === $error) { 634 if ($exit = null === $error) {
597 $error = error_get_last(); 635 $error = error_get_last();
598 } 636 }
599 637
642 * PHP has a compile stage where it behaves unusually. To workaround it, 680 * PHP has a compile stage where it behaves unusually. To workaround it,
643 * we plug an error handler that only stacks errors for later. 681 * we plug an error handler that only stacks errors for later.
644 * 682 *
645 * The most important feature of this is to prevent 683 * The most important feature of this is to prevent
646 * autoloading until unstackErrors() is called. 684 * autoloading until unstackErrors() is called.
685 *
686 * @deprecated since version 3.4, to be removed in 4.0.
647 */ 687 */
648 public static function stackErrors() 688 public static function stackErrors()
649 { 689 {
690 @trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
691
650 self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR); 692 self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR);
651 } 693 }
652 694
653 /** 695 /**
654 * Unstacks stacked errors and forwards to the logger. 696 * Unstacks stacked errors and forwards to the logger.
697 *
698 * @deprecated since version 3.4, to be removed in 4.0.
655 */ 699 */
656 public static function unstackErrors() 700 public static function unstackErrors()
657 { 701 {
702 @trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
703
658 $level = array_pop(self::$stackedErrorLevels); 704 $level = array_pop(self::$stackedErrorLevels);
659 705
660 if (null !== $level) { 706 if (null !== $level) {
661 $errorReportingLevel = error_reporting($level); 707 $errorReportingLevel = error_reporting($level);
662 if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) { 708 if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) {
688 new UndefinedFunctionFatalErrorHandler(), 734 new UndefinedFunctionFatalErrorHandler(),
689 new UndefinedMethodFatalErrorHandler(), 735 new UndefinedMethodFatalErrorHandler(),
690 new ClassNotFoundFatalErrorHandler(), 736 new ClassNotFoundFatalErrorHandler(),
691 ); 737 );
692 } 738 }
739
740 private function cleanTrace($backtrace, $type, $file, $line, $throw)
741 {
742 $lightTrace = $backtrace;
743
744 for ($i = 0; isset($backtrace[$i]); ++$i) {
745 if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) {
746 $lightTrace = array_slice($lightTrace, 1 + $i);
747 break;
748 }
749 }
750 if (!($throw || $this->scopedErrors & $type)) {
751 for ($i = 0; isset($lightTrace[$i]); ++$i) {
752 unset($lightTrace[$i]['args'], $lightTrace[$i]['object']);
753 }
754 }
755
756 return $lightTrace;
757 }
693 } 758 }