错误处理
CodeIgniter 通过异常构建错误报告系统,包括 SPL 集合,以及框架提供的几个异常。
根据您的环境设置,当抛出错误或异常时,默认操作是显示详细的错误报告,除非应用程序在 production
环境下运行。在 production
环境中,会显示更通用的消息,以保持用户最佳体验。
使用异常
本节是针对新手程序员或不熟悉使用异常的开发人员的快速概述。
异常是当异常被“抛出”时发生的事件。这会停止脚本的当前流程,然后执行将发送到错误处理程序,该处理程序会显示相应的错误页面。
<?php
throw new \Exception('Some message goes here');
如果您正在调用可能抛出异常的方法,可以使用 try/catch
块捕获该异常。
<?php
try {
$user = $userModel->find($id);
} catch (\Exception $e) {
exit($e->getMessage());
}
如果 $userModel
抛出异常,它会被捕获,并且 catch 块中的代码会被执行。在本例中,脚本会终止,并回显 UserModel
定义的错误消息。
在上面的示例中,我们捕获了任何类型的异常。如果我们只想监视特定类型的异常,例如 UnknownFileException
,我们可以在 catch 参数中指定它。任何其他抛出的异常,并且不是捕获异常的子类,将被传递给错误处理程序。
<?php
try {
$user = $userModel->find($id);
} catch (\CodeIgniter\UnknownFileException $e) {
// do something here...
}
这对于自己处理错误或在脚本结束之前执行清理非常有用。如果您希望错误处理程序按正常方式运行,您可以在 catch 块中抛出一个新的异常。
<?php
try {
$user = $userModel->find($id);
} catch (\CodeIgniter\UnknownFileException $e) {
// do something here...
throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
}
配置
错误报告
默认情况下,CodeIgniter 会在 development
和 testing
环境中显示包含所有错误的详细错误报告,而在 production
环境中不会显示任何错误。
您可以通过设置 CI_ENVIRONMENT
变量来更改您的环境。请参阅 设置环境。
重要
禁用错误报告并不会阻止在发生错误时写入日志。
警告
请注意,您在 .env 文件中的设置会添加到 $_SERVER
和 $_ENV
中。作为副作用,这意味着如果显示详细错误报告,您的安全凭据将公开暴露。
记录异常
默认情况下,除了 404 - 页面未找到异常之外的所有异常都会被记录。这可以通过设置 app/Config/Exceptions.php 的 $log
值来开启或关闭。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Exceptions extends BaseConfig
{
public $log = true;
}
要忽略其他状态码的记录,您可以在同一个文件中设置要忽略的状态码。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Exceptions extends BaseConfig
{
public $ignoredCodes = [404];
}
注意
如果您的当前日志设置没有设置为记录 critical 错误(所有异常都记录为 critical 错误),那么异常的记录可能仍然不会发生。
框架异常
以下框架异常可用
PageNotFoundException
这用于表示 404,页面未找到错误。当抛出时,系统将显示在 app/Views/errors/html/error_404.php 中找到的视图。您应该为您的网站自定义所有错误视图。如果在 app/Config/Routes.php 中,您指定了 404 覆盖,则将调用该覆盖而不是标准 404 页面。
<?php
if (! $page = $pageModel->find($id)) {
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
}
您可以将消息传递到异常中,该消息将在 404 页面上显示在默认消息的位置。
ConfigException
当配置类中的值无效,或者配置类不是正确的类型等时,应该使用此异常。
<?php
throw new \CodeIgniter\Exceptions\ConfigException();
这提供了一个退出代码 3。
DatabaseException
此异常针对数据库错误抛出,例如当无法创建数据库连接或连接暂时丢失时。
<?php
throw new \CodeIgniter\Database\Exceptions\DatabaseException();
这提供了一个退出代码 8。
RedirectException
注意
从 v4.4.0 开始,RedirectException
的命名空间已更改。以前是 CodeIgniter\Router\Exceptions\RedirectException
。之前的类已弃用。
此异常是一个特殊情况,允许覆盖所有其他响应路由,并强制重定向到特定 URI。
<?php
throw new \CodeIgniter\HTTP\Exceptions\RedirectException($uri);
$uri
是相对于 baseURL 的 URI 路径。您也可以提供一个重定向代码来代替默认代码 (302
,"临时重定向")
<?php
throw new \CodeIgniter\HTTP\Exceptions\RedirectException($uri, 301);
此外,从 v4.4.0 开始,可以将实现 ResponseInterface 的类的对象用作第一个参数。此解决方案适用于您需要在响应中添加其他标头或 cookie 的情况。
<?php
$response = \Config\Services::response()
->redirect('https://example.com/path')
->setHeader('Some', 'header')
->setCookie('and', 'cookie');
throw new \CodeIgniter\HTTP\Exceptions\RedirectException($response);
在异常中指定 HTTP 状态代码
版本 4.3.0 中的新增功能。
从 v4.3.0 开始,您可以指定异常类以实现 HTTPExceptionInterface
的 HTTP 状态代码。
当 CodeIgniter 的异常处理程序捕获到实现 HTTPExceptionInterface
的异常时,异常代码将成为 HTTP 状态代码。
在异常中指定退出代码
版本 4.3.0 中的新增功能。
从 v4.3.0 开始,您可以指定异常类以实现 HasExitCodeInterface
的退出代码。
当 CodeIgniter 的异常处理程序捕获到实现 HasExitCodeInterface
的异常时,从 getExitCode()
方法返回的代码将成为退出代码。
记录弃用警告
版本 4.3.0 中的新增功能。
默认情况下,由 error_reporting()
报告的所有错误都将作为 ErrorException
对象抛出。这些包括 E_DEPRECATED
和 E_USER_DEPRECATED
错误。随着 PHP 8.1+ 的使用激增,许多用户可能会看到为 将 null 传递给内部函数的非空参数 抛出的异常。为了简化迁移到 PHP 8.1,您可以指示 CodeIgniter 记录弃用,而不是抛出它们。
首先,确保您的 Config\Exceptions
副本已更新为包含两个新属性,并按如下方式设置。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use Psr\Log\LogLevel;
class Exceptions extends BaseConfig
{
// ... other properties
public bool $logDeprecations = true;
public string $deprecationLogLevel = LogLevel::WARNING; // this should be one of the log levels supported by PSR-3
}
接下来,根据您在 Config\Exceptions::$deprecationLogLevel
中设置的日志级别,检查 Config\Logger::$threshold
中定义的日志器阈值是否涵盖弃用日志级别。如果不是,请相应调整。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Logger extends BaseConfig
{
// .. other properties
public $threshold = 5; // originally 4 but changed to 5 to log the warnings from the deprecations
}
之后,后续的弃用将被记录而不是抛出。
此功能也适用于用户弃用。
<?php
@trigger_error('Do not use this class!', E_USER_DEPRECATED);
// Your logs should contain a record with a message like: "[DEPRECATED] Do not use this class!"
为了测试您的应用程序,您可能希望在弃用时始终抛出异常。您可以通过将环境变量 CODEIGNITER_SCREAM_DEPRECATIONS
设置为真值来配置此选项。
自定义异常处理程序
版本 4.4.0 中新增。
如果您需要更精细地控制异常的显示方式,您现在可以定义自己的处理程序并指定它们适用的情况。
定义新的处理程序
第一步是创建一个新的类,该类实现 CodeIgniter\Debug\ExceptionHandlerInterface
。您也可以扩展 CodeIgniter\Debug\BaseExceptionHandler
。此类包含默认异常处理程序使用的许多实用程序方法。新的处理程序必须实现一个方法:handle()
<?php
namespace App\Libraries;
use CodeIgniter\Debug\BaseExceptionHandler;
use CodeIgniter\Debug\ExceptionHandlerInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Throwable;
class MyExceptionHandler extends BaseExceptionHandler implements ExceptionHandlerInterface
{
// You can override the view path.
protected ?string $viewPath = APPPATH . 'Views/exception/';
public function handle(
Throwable $exception,
RequestInterface $request,
ResponseInterface $response,
int $statusCode,
int $exitCode
): void {
$this->render($exception, $statusCode, $this->viewPath . "error_{$statusCode}.php");
exit($exitCode);
}
}
此示例定义了通常需要的最少代码量 - 显示视图并使用正确的退出代码退出。但是,BaseExceptionHandler
提供了许多其他辅助函数和对象。
配置新的处理程序
在 **app/Config/Exceptions.php** 配置文件的 handler()
方法中告诉 CodeIgniter 使用您的新异常处理程序类。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Debug\ExceptionHandler;
use CodeIgniter\Debug\ExceptionHandlerInterface;
use Throwable;
class Exceptions extends BaseConfig
{
// ...
public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
{
return new ExceptionHandler($this);
}
}
您可以使用应用程序所需的任何逻辑来确定是否应该处理异常,但最常见的两种方法是检查 HTTP 状态代码或异常类型。如果您的类应该处理它,则返回该类的新的实例。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Debug\ExceptionHandlerInterface;
use CodeIgniter\Exceptions\PageNotFoundException;
use Throwable;
class Exceptions extends BaseConfig
{
// ...
public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
{
if (in_array($statusCode, [400, 404, 500], true)) {
return new \App\Libraries\MyExceptionHandler($this);
}
if ($exception instanceof PageNotFoundException) {
return new \App\Libraries\MyExceptionHandler($this);
}
return new \CodeIgniter\Debug\ExceptionHandler($this);
}
}