Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/.idea
/assets/*.css
/assets/*.map
/composer.lock
Expand Down
39 changes: 35 additions & 4 deletions collectors/php_errors.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public function set_up() {
$prior_error = error_get_last();

// Non-fatal error handler:
$this->previous_error_handler = set_error_handler( array( $this, 'error_handler' ), ( E_ALL ^ QM_ERROR_FATALS ) );
// To support error handler chaining, we need to set our error handler with E_ALL error_levels.
$this->previous_error_handler = set_error_handler( array( $this, 'error_handler' ) );

// Fatal error and uncaught exception handler:
$this->previous_exception_handler = set_exception_handler( array( $this, 'exception_handler' ) );
Expand Down Expand Up @@ -176,6 +177,12 @@ public function exception_handler( $e ) {
* @return bool
*/
public function error_handler( $errno, $message, $file = null, $line = null, $context = null, $do_trace = true ) {
if ( $errno & QM_ERROR_FATALS ) {
// Do not proceed with fatal errors.
// phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
return $this->fallback_error_handler( func_get_args() );
}

$type = null;

/**
Expand Down Expand Up @@ -216,11 +223,13 @@ public function error_handler( $errno, $message, $file = null, $line = null, $co
}

if ( null === $type ) {
return false;
// phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
return $this->fallback_error_handler( func_get_args() );
}

if ( ! class_exists( 'QM_Backtrace' ) ) {
return false;
// phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
return $this->fallback_error_handler( func_get_args() );
}

$error_group = 'errors';
Expand All @@ -245,7 +254,14 @@ public function error_handler( $errno, $message, $file = null, $line = null, $co
// Intentionally skip reporting these core warnings. They're a distraction when developing offline.
// The failed HTTP request will still appear in QM's output so it's not a big problem hiding these warnings.
if ( false !== strpos( $message, self::$unexpected_error ) ) {
return false;
// phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
return $this->fallback_error_handler( func_get_args() );
}

// If the fallback error handler returns true, the error was suppressed.
// phpcs:ignore PHPCompatibility.FunctionUse.ArgumentFunctionsReportCurrentValue.NeedsInspection
if ( $this->fallback_error_handler( func_get_args() ) ) {
return true;
}

$trace = new QM_Backtrace();
Expand Down Expand Up @@ -289,6 +305,21 @@ public function error_handler( $errno, $message, $file = null, $line = null, $co

}

/**
* Fallback error handler.
*
* @param mixed[] $args Arguments.
*
* @return bool
* @noinspection PhpTernaryExpressionCanBeReplacedWithConditionInspection
*/
private function fallback_error_handler( array $args ): bool {
return null === $this->previous_error_handler ?
// Use standard error handler.
false :
(bool) call_user_func_array( $this->previous_error_handler, $args );
}

/**
* @param string $error
* @param mixed[] $e
Expand Down