public function __invoke($error, ServerRequestInterface $request, ResponseInterface $response, callable $next) { $data = ['type' => get_class($error), 'message' => $error->getMessage(), 'file' => $this->formatDir($error->getFile()) . ':' . $error->getLine()]; $inspector = new Inspector($error); $frameData = []; foreach ($inspector->getFrames() as $frame) { $frameData[] = ['file' => $this->formatDir($frame->getFile()) . ':' . $frame->getLine(), 'method' => $frame->getClass() . '::' . $frame->getFunction()]; } $data['trace'] = $frameData; return new JsonResponse(['error' => $data], $this->getStatusCode($error, $response)); }
public static function formatExceptionPlain(Inspector $inspector) { $message = $inspector->getException()->getMessage(); $frames = $inspector->getFrames(); $plain = $inspector->getExceptionName(); $plain .= ' thrown with message "'; $plain .= $message; $plain .= '"' . "\n\n"; $plain .= "Stacktrace:\n"; foreach ($frames as $i => $frame) { $plain .= "#" . (count($frames) - $i - 1) . " "; $plain .= $frame->getClass() ?: ''; $plain .= $frame->getClass() && $frame->getFunction() ? ":" : ""; $plain .= $frame->getFunction() ?: ''; $plain .= ' in '; $plain .= $frame->getFile() ?: '<#unknown>'; $plain .= ':'; $plain .= (int) $frame->getLine() . "\n"; } return $plain; }
public function getFrames() { $frames_obj = parent::getFrames()->getArray(); //If it's a PHP error we can skip all classes before it, as those are handlers' exceptions if ($frames_obj[0]->getClass() == 'Whoops\\Exception\\ErrorException') { //Removing all object wrappers and getting list of raw frames $frames = array_map(function ($frame) { return $frame->getRawFrame(); }, $frames_obj); $removable_keys = [0]; while (array_key_exists('class', next($frames))) { $removable_keys[] = key($frames); } foreach ($removable_keys as $key) { unset($frames[$key]); } $frames = array_merge($frames); $frames_obj = new FrameCollection($frames); } return $frames_obj; }
/** * Override default implementation for two reasons: * ErrorException is caught by WhoopsErrorHandler, so it will * have a line and would be displayed by Whoops. * The default behavior of Whoops in case of an ErrorException * without a line is to only display one frame, we instead display * a full stack trace up to the actual error. * The stack trace is cut off at CApplication::handleError. * @return \Whoops\Exception\FrameCollection */ public function getFrames() { if ($this->frames === null) { $exception = $this->getException(); if (!$exception instanceof \Whoops\Exception\ErrorException) { $this->frames = parent::getFrames(); return $this->frames; } $frames = $exception->getTrace(); foreach ($frames as $i => $frame) { unset($frames[$i]); if ($frame['class'] === 'CApplication' && $frame['function'] === 'handleError') { break; } } $frames = array_values($frames); $this->frames = new FrameCollection($frames); // ErrorException doesn't have previous exception, // skip adding its frames } return $this->frames; }