was raised in. * @param int $line the line number the error was raised at. * @return bool whether the normal error handler continues. * * @throws ErrorException */ public function handleError($code, $message, $file, $line) { if (error_reporting() & $code) { // load ErrorException manually here because autoloading them will not work // when error occurs while autoloading a class if (!class_exists('yii\\base\\ErrorException', false)) { require_once __DIR__ . '/ErrorException.php'; } $exception = new ErrorException($message, $code, $code, $file, $line); if (PHP_VERSION_ID < 70400) { // prior to PHP 7.4 we can't throw exceptions inside of __toString() - it will result a fatal error $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); array_shift($trace); foreach ($trace as $frame) { if ($frame['function'] === '__toString') { $this->handleException($exception); if (defined('HHVM_VERSION')) { flush(); } exit(1); } } } throw $exception; } return false; } /** * Handles fatal PHP errors. */ public function handleFatalError() { $this->_memoryReserve = null; if (!empty($this->_workingDirectory)) { // fix working directory for some Web servers e.g. Apache chdir($this->_workingDirectory); // flush memory $this->_workingDirectory = null; } $error = error_get_last(); if ($error === null) { return; } // load ErrorException manually here because autoloading them will not work // when error occurs while autoloading a class if (!class_exists('yii\\base\\ErrorException', false)) { require_once __DIR__ . '/ErrorException.php'; } if (!ErrorException::isFatalError($error)) { return; } if (!empty($this->_hhvmException)) { $this->exception = $this->_hhvmException; } else { $this->exception = new ErrorException( $error['message'], $error['type'], $error['type'], $error['file'], $error['line'] ); } unset($error); $this->logException($this->exception); if ($this->discardExistingOutput) { $this->clearOutput(); } $this->renderException($this->exception); // need to explicitly flush logs because exit() next will terminate the app immediately Yii::getLogger()->flush(true); if (defined('HHVM_VERSION')) { flush(); } $this->trigger(static::EVENT_SHUTDOWN); // ensure it is called after user-defined shutdown functions register_shutdown_function(function () { exit(1); }); } /** * Renders the exception. * @param \Throwable $exception the exception to be rendered. */ abstract protected function renderException($exception); /** * Logs the given exception. * @param \Throwable $exception the exception to be logged * @since 2.0.3 this method is now public. */ public function logException($exception) { $category = get_class($exception); if ($exception instanceof HttpException) { $category = 'yii\\web\\HttpException:' . $exception->statusCode; } elseif ($exception instanceof \ErrorException) { $category .= ':' . $exception->getSeverity(); } Yii::error($exception, $category); } /** * Removes all output echoed before calling this method. */ public function clearOutput() { // the following manual level counting is to deal with zlib.output_compression set to On for ($level = ob_get_level(); $level > 0; --$level) { if (!@ob_end_clean()) { ob_clean(); } } } /** * Converts an exception into a PHP error. * * This method can be used to convert exceptions inside of methods like `__toString()` * to PHP errors because exceptions cannot be thrown inside of them. * @param \Throwable $exception the exception to convert to a PHP error. * @return never */ public static function convertExceptionToError($exception) { trigger_error(static::convertExceptionToString($exception), E_USER_ERROR); } /** * Converts an exception into a simple string. * @param \Throwable $exception the exception being converted * @return string the string representation of the exception. */ public static function convertExceptionToString($exception) { if ($exception instanceof UserException) { return "{$exception->getName()}: {$exception->getMessage()}"; } if (YII_DEBUG) { return static::convertExceptionToVerboseString($exception); } return 'An internal server error occurred.'; } /** * Converts an exception into a string that has verbose information about the exception and its trace. * @param \Throwable $exception the exception being converted * @return string the string representation of the exception. * * @since 2.0.14 */ public static function convertExceptionToVerboseString($exception) { if ($exception instanceof Exception) { $message = "Exception ({$exception->getName()})"; } elseif ($exception instanceof ErrorException) { $message = (string)$exception->getName(); } else { $message = 'Exception'; } $message .= " '" . get_class($exception) . "' with message '{$exception->getMessage()}' \n\nin " . $exception->getFile() . ':' . $exception->getLine() . "\n\n" . "Stack trace:\n" . $exception->getTraceAsString(); return $message; } }