错误处理
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
定义的错误信息。
捕获特定异常
上例中我们捕获所有类型的 Exception。若只需捕获特定类型的异常(如 DataException
),可在 catch 参数中指定。其他未被捕获的异常类型将传递给错误处理程序:
<?php
use CodeIgniter\Database\Exceptions\DataException;
try {
$user = $userModel->find($id);
} catch (DataException $e) {
// do something here...
}
这种方式便于自行处理错误或在脚本结束前执行清理操作。若希望错误处理程序按常规方式处理,可在 catch 块中重新抛出异常:
<?php
use CodeIgniter\Database\Exceptions\DataException;
try {
$user = $userModel->find($id);
} catch (DataException $e) {
// do something here...
throw new \RuntimeException($e->getMessage(), $e->getCode(), $e);
}
配置
错误报告
当 PHP ini 设置中的 display_errors
启用时,CodeIgniter 将显示包含所有错误的详细报告
默认情况下,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 bool $log = true;
// ...
}
要忽略其他状态码的日志记录,可在同一文件中设置:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Exceptions extends BaseConfig
{
// ...
public array $ignoreCodes = [404];
// ...
}
备注
如果当前 日志设置 未配置记录 critical
级别错误(所有异常均按此级别记录),异常可能仍不会被记录。
记录弃用警告
在 4.3.0 版本加入.
在 v4.3.0 之前,所有通过 error_reporting()
报告的错误都会被抛出为 ErrorException
对象。
随着 PHP 8.1+ 的普及,用户可能会遇到因 向内部函数的非空参数传递 null 值 导致的异常抛出。
为简化迁移到 PHP 8.1 的过程,从 v4.3.0 开始,CodeIgniter 新增了仅记录弃用错误(E_DEPRECATED
和 E_USER_DEPRECATED
)而不将其作为异常抛出的功能。
默认情况下,CodeIgniter 在开发环境中仅记录弃用警告而不抛出异常。在生产环境中,既不记录也不抛出异常。
配置
该功能的配置步骤如下: 首先确保 ConfigExceptions 已更新并包含以下两个新属性:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
use Psr\Log\LogLevel;
class Exceptions extends BaseConfig
{
// ...
public bool $logDeprecations = true; // If set to false, an exception will be thrown.
// ...
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
{
// ...
// This must contain the log level (5 for LogLevel::WARNING) corresponding to $deprecationLogLevel.
public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
// ...
}
配置完成后,后续弃用警告将按配置记录而不作为异常抛出。
该功能也支持用户自定义弃用警告:
<?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
为真值。
框架异常
异常设计
自 v4.6.0 起,框架抛出的所有异常类:
实现
CodeIgniter\Exceptions\ExceptionInterface
继承
CodeIgniter\Exceptions\LogicException
或CodeIgniter\Exceptions\RuntimeException
备注
框架仅抛出上述类型异常,但 PHP 或其他使用的库可能抛出其他异常。
框架抛出的两种基础异常类:
LogicException
CodeIgniter\Exceptions\LogicException
继承自 \LogicException
。该异常表示程序逻辑错误,应直接通过修改代码修复。
RuntimeException
CodeIgniter\Exceptions\RuntimeException
继承自 \RuntimeException
。该异常在运行时发生错误时抛出。
其他可用框架异常:
PageNotFoundException
用于触发 404 页面未找到错误:
<?php
use CodeIgniter\Exceptions\PageNotFoundException;
$page = $pageModel->find($id);
if ($page === null) {
throw PageNotFoundException::forPageNotFound();
}
可传递自定义消息替代默认的 404 页面信息。默认 404 视图文件位置参见 HTTP 状态码与错误视图。
如果在 app/Config/Routing.php 或 app/Config/Routes.php 中配置了 404 重写,将调用该覆盖配置而非标准 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
,该旧类已在 v4.6.0 移除。
此特殊异常允许覆盖其他响应路由并强制重定向到指定 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 的对象。此方案适用于需要添加额外头信息或 cookies 的场景:
<?php
$response = service('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 起,可通过让异常类实现 CodeIgniter\Exceptions\HTTPExceptionInterface
来指定 HTTP 状态码。
当 CodeIgniter 异常处理器捕获到实现 HTTPExceptionInterface
的异常时,异常代码将作为 HTTP 状态码。
HTTP 状态码与错误视图
异常处理器会显示与 HTTP 状态码对应的错误视图(如果存在)。
例如,PageNotFoundException
实现了 HTTPExceptionInterface
,其异常代码 404
将作为 HTTP 状态码。当该异常被抛出时:
网页请求会显示 app/Views/errors/html 目录下的 error_404.php
CLI 请求会显示 app/Views/errors/cli 目录下的 error_404.php
若无对应 HTTP 状态码的视图文件,将显示 production.php 或 error_exception.php。
备注
若 PHP ini 设置中 display_errors
开启,将选择 error_exception.php 并显示详细错误报告。
建议在 app/Views/errors/html 目录下自定义所有错误视图。
可为特定 HTTP 状态码创建错误视图。例如创建 “400 Bad Request” 错误视图需添加 error_400.php。
警告
若存在对应 HTTP 状态码的错误视图文件,异常处理器将始终显示该文件。必须确保视图文件在生产环境中不会自行显示详细错误信息。
在异常中指定退出码
在 4.3.0 版本加入.
自 v4.3.0 起,可通过让异常类实现 CodeIgniter\Exceptions\HasExitCodeInterface
来指定退出码。
当 CodeIgniter 异常处理器捕获到实现 HasExitCodeInterface
的异常时,将从 getExitCode()
方法获取退出码。
自定义异常处理器
在 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()
方法中指定使用新异常处理器类:
<?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);
}
}