backtrace = $backtrace; } /** * Determine if the backtrace was from an unhandled error. * * @return bool */ public function isUnhandled() { foreach ($this->backtrace as $frame) { $this->processFrame($frame); // stop iterating early if we know we're done if ($this->state === self::STATE_DONE) { break; } } return $this->unhandled; } /** * @param array $frame * * @return void */ private function processFrame(array $frame) { if (!isset($frame['class'])) { return; } $class = $frame['class']; switch ($this->state) { case self::STATE_FRAMEWORK_HANDLER: // if this class is a framework exception handler and the function // matches self::HANDLER_METHOD, we can move on to searching for // the caller if ($this->isFrameworkExceptionHandler($class) && isset($frame['function']) && $frame['function'] === self::HANDLER_METHOD ) { $this->state = self::STATE_HANDLER_CALLER; } break; case self::STATE_HANDLER_CALLER: // if this is an app exception handler or a framework class, we // can move on to determine if this was unhandled or not if ($this->isAppExceptionHandler($class) || $this->isVendor($class)) { $this->state = self::STATE_IS_UNHANDLED; } break; case self::STATE_IS_UNHANDLED: // we are only interested in running this once so move immediately // into the "done" state. This ensures we only check the frame // immediately before the caller of the exception handler $this->state = self::STATE_DONE; // if this class is internal to the framework then the exception // was unhandled if ($this->isVendor($class)) { $this->unhandled = true; } break; } } /** * Does the given class belong to a vendor namespace? * * @see self::VENDOR_NAMESPACES * * @param string $class * * @return bool */ private function isVendor($class) { return $this->isInNamespace($class, self::LARAVEL_VENDOR_NAMESPACE) || $this->isInNamespace($class, self::LUMEN_VENDOR_NAMESPACE) || $this->isInNamespace($class, self::COLLISION_VENDOR_NAMESPACE); } /** * Check if the given class is in the given namespace. * * @param string $class * @param string $namespace * * @return bool */ private function isInNamespace($class, $namespace) { return substr($class, 0, strlen($namespace)) === $namespace; } /** * Is the given class Laravel or Lumen's exception handler? * * @param string $class * * @return bool */ private function isFrameworkExceptionHandler($class) { return $class === self::LARAVEL_HANDLER_CLASS || $class === self::LUMEN_HANDLER_CLASS; } /** * Is the given class an App's exception handler? * * @param string $class * * @return bool */ private function isAppExceptionHandler($class) { return $class === self::LARAVEL_APP_EXCEPTION_HANDLER || $class === self::LUMEN_APP_EXCEPTION_HANDLER; } }