1、错误处理的分类
语法错误: 违背了PHP程序语言的规则错误,称之为语法错误。
运行错误: 经过语法错误检测后,将开始运行 PHP 代码,在此发生的错误为运行时错误。
逻辑错误: 逻辑错误是指程序开发过程中由于业务逻辑造成错误。
print_r(数组类型) //没有以分号结束语句,报语法错误
/*
加载不存在文件
连接数据库失败
远程请求失败
函数或类不存在
*/
require 'request.php'; //因为加载不存在文件,所以会发生运行时错误
echo (10/0); //逻辑错误,这IDE都会检测到,一般都有提示
//逻辑错误
for ($i = 0; $i < 5; $i--) {
echo $i;
}
2、常见错误报告类型
值 | 常量 | 描述 |
---|---|---|
1 | E_ERROR | 致命的运行时错误。这类错误一般是不可恢复的情况,例如内存分配导致的问题。后果是导致脚本终止不再继续运行 |
2 | E_WARNING | 运行时警告 (非致命错误)。仅给出提示信息,但是脚本不会终止运行。 |
8 | E_NOTICE | 运行时通知。表示脚本遇到可能会表现为错误的情况。 |
64 | E_COMPILE_ERROR | 致命编译时错误。类似 E_ERROR |
2048 | E_STRICT | 启用 PHP 对代码的修改建议,以确保代码具有最佳的互操作性和向前兼容性。 |
8192 | E_DEPRECATED | 运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。 |
8191 | E_ALL | 所有错误和警告,除级别 E_STRICT 以外。 |
注意:修改 php.ini
配置文件, display_errors = On
即开启或者关闭错误显示。
关闭警告与致命错误
error_reporting(~E_WARNING & ~E_COMPILE_ERROR);
require('a');
显示除通知外的所有错误
error_reporting(E_ALL & ~E_NOTICE);
echo $arrays;
关闭错误显示
error_reporting(0);
3、异常处理
基本语法:
try{
//逻辑代码
}catch(){
//捕获异常时候的处理
}
注意: 需要手动抛出异常,这与其他语言不同,异常使用 try…cache 触发。
手动抛出异常的方法:
throw new 错误类型($message, $code);
注意:可以设置多个catch,参数Exception 或者继承Exception的类
Exception 类的方法:
方法 | 说明 | 重写 |
---|---|---|
getFile | 产生异常错误的文件 | NO,final |
getCode | 错误码 | NO,final |
getLine | 错误行号 | NO,final |
getMessage | 错误消息 | NO,final |
__toString | 对象转字符串后输出内容 | YES |
finally: 需要放在 catch
后,finally
无论是否抛出异常都会执行。
登录异常处理的例子:
class LoginException extends Exception {
// 构造函数
public function __construct($message, $code = 0, Throwable $previous = null) {
parent::__construct($message, $code, $previous);
}
// 将异常对象转为字符串
public function __toString() {
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
// 自定义异常处理函数
public function logError() {
// 记录登录错误日志
error_log("登录异常: " . $this->getMessage());
}
}
function loginUser($username, $password) {
// 模拟登录逻辑
if ($username !== "admin" || $password !== "password") {
throw new LoginException("无效的用户名或密码。");
}
// 登录成功
return true;
}
try {
$loggedIn = loginUser("guest", "pass123"); // 尝试登录
if ($loggedIn) {
echo "登录成功!";
}
} catch (LoginException $e) { // 捕获登录异常
echo "登录失败:" . $e->getMessage() . "\n";
$e->logError(); // 调用自定义异常处理函数,记录登录错误日志
} catch (Exception $e) { // 捕获其他异常
echo "发生了一个错误:" . $e->getMessage() . "\n";
}
操作数据库多表联动时捕获异常回滚数据:
try {
// 连接数据库
$db = new PDO("mysql:host=localhost;dbname=mydatabase", "username", "password");
// 开始事务
$db->beginTransaction();
// 执行一系列数据库操作
$db->exec("INSERT INTO users (name, email) VALUES ('John Doe', '[email protected]')");
$db->exec("INSERT INTO orders (user_id, product_id, quantity) VALUES (1, 1, 2)");
// 提交事务
$db->commit();
} catch (PDOException $e) { // 捕获 PDO 异常
// 回滚事务
$db->rollBack();
// 记录异常日志
error_log("数据库操作异常: " . $e->getMessage());
// 输出错误信息
echo "发生了一个数据库操作异常:" . $e->getMessage() . "\n";
}
总结:
异常处理应该是有针对性的:捕获和处理那些你知道如何处理的异常类型,而将未知或不可处理的异常传递给更上层的代码进行处理。
使用合适的异常类型:PHP 中有许多内置的异常类型,如 Exception
、InvalidArgumentException
、RuntimeException
等。选择合适的异常类型可以更好地组织和识别代码中的异常情况。
按照异常类型的顺序进行捕获:在 catch
块中,应该按照特定异常类型到更一般异常类型的顺序进行排序。这样可以确保异常被正确捕获,并且避免特定的异常被更一般的异常类型捕获导致无法执行特定的异常处理逻辑。
使用多个 catch
块进行处理:根据不同的异常类型,使用多个 catch
块来处理不同类型的异常。这样可以更细粒度地处理异常,并根据需要执行特定的逻辑。
考虑添加日志或错误记录:在异常处理过程中,可以将异常信息记录到日志文件或错误日志中,以便后续的故障排查和分析。
避免过度捕获异常:不要过度捕获异常,这可能导致隐藏潜在的问题或掩盖错误。只捕获你知道如何处理的异常,并将其他未处理的异常传递给更上层的代码进行处理。
使用 finally
块(可选):finally
块中的代码无论是否发生异常都会执行。它通常用于释放资源或执行清理操作,以确保在异常发生时资源得到正确处理。
抛出自定义异常:通过定义自定义异常类,可以更好地组织和标识特定类型的异常。这样可以使代码更加清晰,并提供更丰富的异常信息。