PHP & 理解 Laravel 中 Errors & Exceptions (错误与异常) 的作用、使用

一、介绍

文本将从PHP原生错误/异常 讲解到 Laravel 错误/异常,耐心看完,相信你会有所收获。

1.1 什么是错误

在 PHP 中,最常见错误的级别有

错误类型解释
Deprecated比如 API 过期 ,属于低级错误
Notice变量未定义
Warning结果不符合逻辑,比如函数里面 $num + 100,但 $num 传递进来的是 ‘ab’
Fetal致命错误,直接终止运行后面的运行,比如调用不存在的函数
Prase最高级别错误,以上的都是运行期间报错,这里直接在语法解析期间报错。

给上面对应的错误类型举几个例子

<?php
// Notice 级别:未定义变量
echo($abc);

function foo($num){
  echo $num + 100;
}
// Warning 级别:传递错误的值
foo('hello');

// Fetal 级别:致命级别,导致后面的程序不在执行,比如调用不存在的函数
// throw new Error("你也可以手动通过 new error 抛出致命错误");
abc();

echo "这句话将不会被打印出来";

// Prase  级别:最高级别,以上都是运行期间错误,这里直接在语法解析期间错误
// 为了上面能正常运行,这里先注释掉
// echo ++;

在这里插入图片描述

另外,PHP 也提供了 set_error_handler ,此函数将会把所有把错误交给你接管,而 Laravel 正是利用了此函数进行重写,比如格式化输出、将所有错误以异常抛出去等等,具体怎么使用这里不在讲述,可参考文档。

1.2 什么是异常

PHP 是在 PHP5 后才引入异常的,每个语言对异常的理解各有不同,比如在 PHP 中 除 0 它是一个 warning 级别错误行为而不是异常,而在 JAVA 中它是属于异常行为。

$abc = 10 / 0;
// 10 / 0 属于报错 warning 行为,并不属于异常。
echo $abc;

所以很多时候异常都是由我们通过 if else 来手动控制抛出的,比如用户手机未输入

<?php
try {
	if (empty($_GET['phone'])) {
		throw new Exception('请输入手机号'); // 手动抛出
	}
} catch (Exception $e) {
	echo $e->getMessage(); // 接受异常传递过来的消息,我们直接打印。
}

在这里插入图片描述

注意:捕获异常需要用到 try / catch,如果直接在外部使用 throw new Exception,它将会是一个错误行为

throw new Exception('请输入手机号');

在这里插入图片描述

其实异常更多的作用是用来进行一些补救措施,比如数据库事务的回滚,
举个简单例子:用户提交订单

beginTransaction(); // 启动事务
try {
	DB::update('从数据库中扣掉商品库存');
	// 发现用户未输入手机号,我们手动抛出异常
	if (empty($_POST['phone'])) {
		throw new Exceptions('请输入手机');
	}
	commit(); // 提交事务:由于上面抛出异常,这里不会触发。
} catch(Exception $e) {
	rollback(); // 回滚事务:这里捕获到了异常,所以对扣掉库存这一操作进行回滚。
}

值得注意的是,在 PHP 7 以前,try/catch 是捕获不了错误的,比如调用不存在的函数

try {
	abc();
} catch(Exception $e) {
	echo '函数不存在' . $e->getMessage();
}

在这里插入图片描述

后来为了让部分错误能够捕获到,在 PHP 7 中引入了 Throwable ,可以说是 Exception 的升级版,但它只能对部分错误进行捕获,像下面的调用未知函数就可以捕获到。

try {
	abc();
	// 你也可以像 Exception 一样手动抛出 
	// throw new Throable("xxxx");
} catch (Throwable $e) {
	echo "函数不存在:" . $e->getMessage();
}

在这里插入图片描述

而像下面的访问未定义变量,依然还是捕获不了,直接一个报错行为。

try {
	echo $abc;
} catch (Throwable $e){
	echo "变量不存在" . $e->getMessage();
}

在这里插入图片描述

另外,PHP 也提供了 set_exception_handler ,次函数将所有异常都交给你接管, 显然 Laravel 也不会放过这个函数。

好了,接下来我们开始进入 Laravel

二、Laravel 中的错误与异常

理解了 PHP 中的基本错误/异常后,现在我们来开始使用 Laravel 中的错误/异常。

本文假设你已创建 Laravel 项目。

2.1 错误与异常的默认处理

我们首先抛出一个错误,看看在 Laravel 中会发生什么,假设我们有个 test 路由。

// route/web.php
use Illuminate\Support\Facades\Route;
Route::get('test', function(){
	echo $abc; // 打印不存在的变量。
});

接下来访问 http://localhost:8000/test ,输出如下:
在这里插入图片描述
可以看到,Laravel 展示的是一个美化过的错误页面。

另外我们也知道原生 try/catch 是无法捕获到未知变量这种错误行为的,但 Laravel 为我们做到了

use Illuminate\Support\Facades\Route;
Route::get('/test', function(){
	try  {
		echo $abc;
	} catch(Exception $e) {
		echo '变量不存在:'.$e->getMessage();
	}
});

在这里插入图片描述
很明显 Laravel 利用 set_error_handler 对错误进行了重写并以异常的形式抛出,这点值得称赞。

2.2 关于错误/异常发生后,Laravel 的日志记录问题

每次发生异常或者报错 Laravel 都会为我们写入日志文件里,下面是针对 try 内外的情况进行分析。

try 外

  1. 两者都被记录在 app/storage/logs 里面
echo $abc;
throw new Exception("抛出异常");

try 内

  1. 异常不会被记录,但可以手动调用 report() 进行记录,而错误会自动被记录。
try {
	throw new Exception("抛出异常"); // 不会被记录,只能在 catch 中手动记录。
	// echo $abc; // 会自动被记录
} catch (Exception $e) {
	report(); // 手动记录
	// .. do something
}

我们只需记得:使用 try/catch 后,权限交给用户,不使用则交给 Laravel

2.3 给 log 日志添加额外数据

每次发生异常或错误时我们想要给日志增加额外数据方便后续排查,需要怎么做?很简单,只需在 app/Exceptions/Handler.php 里面新增 context 方法进行添加即可,比如

// app/Exceptions/Handler.php =============
public function context() {
   return array_merge(parent::context(), [
        'user' => 'Cookcyq',
    ]);
}

在这里插入图片描述

2.4 自定义错误/异常页面

如上所知,默认情况下 Laravel 会自动返回一个美化过的页面,如果你不喜欢这种风格,Laravel 还提供了 $this->renderable 让你重写,我们来改造一下,依然是在 app/Exceptions/Handler.php 里面修改。

// app/Exceptions/Handler.php ==================
public function register(){
    // 重写
   $this->renderable(function(Throwable $e) {
       return response([
           'msg' => $e->getMessage(),
           'line' => $e->getLine(),
       ]);
   });
}

// route/web.php ==================
use Illuminate\Support\Facades\Route;
Route::get('/test', function(){
	echo $abc;
	// 或 throw new Exception("Something is wrong.");
});

现在我们来访问 http://localhost:8000/test
在这里插入图片描述

可以看到页面变成我们自定义的了,想要更多日志操作可参考官方文档:https://laravel.com/docs/9.x/errors

三、Laravel 自定义异常

由于上面的 $this->renderable 是全局性的,每个异常/错误都会触发,有时我们并不像这样做,而是仅针对某个功能,其它则按照 Laravel 默认模板正常显示,比如我们有个注册,如果注册有问题,就抛出注册异常,正好 Laravel 也为我们提供了这种能力。

  1. 首先在 app/Exceptions/目录下新增 RegisterException.php 文件,代码如下:
<?php
namespace App\Exceptions;
 
use Exception;
class RegisterException extends Exception
{
    /**
     * RegisterException 添加日志额外内容,可与全局 context 累加。
     */
    public function context() {
      return ['myException' => 'Cookcyq'];
    }
  	
  	/* 自定义响应内容 */
    public function render($request) {
      return response([
        'msg' => $this->getMessage()
      ]);
    }
}
  1. route/web.php 代码如下
use Illuminate\Support\Facades\Route;
use App\Exceptions\RegisterException;
Route::get('/test', function(){
	throw new RegisterException("Please make sure your account or password are correct.");
});

效果
在这里插入图片描述

四、业务案例

在实际业务中,假如我们是 API 提供者,我们需要对传递进来的参数不正确、残缺等情况进行响应处理,这个时候我们就可以利用自定义 Exception。

  1. 还是老样子,首先在 app/Exceptions/ 新建 MyException.php 文件,代码如下
<?php
namespace App\Exceptions;
 
use Exception;
class MyException extends Exception
{
    public function render($request) {
      $data = [
        'msg' => $this->getMessage(),
        'status' => $this->code
      ];
      // JSON_UNESCAPED_UNICODE 解决中文变成 unicode 问题。
      return response()->json($data)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }
}
  1. 定义 /login 路由,代码如下
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Exceptions\MyException;
Route::get('/login', function(Request $request){
	if (empty($request['phone'])) {
		throw new MyException("请输入手机", -10000);
	}
	if (empty($request['password'])) {
		throw new MyException("请输入密码", -10000);
	}
	return response([
		'msg' 		=> '登录成功',
		'status' 	=> 10000,
	]);
});

此时我们访问:http://localhost:8000/login
在这里插入图片描述

访问 http://localhost:8000/login?phone=10086&password=secret
在这里插入图片描述
怎么样,异常的处理是不是很简单?

总结

Laravel 利用了 set_error_handler / set_exception_handler 对错误/异常进行了重写,给开发者带来了许多便利之处。

希望本文能让你对 PHP 原生和 Laravel 中错误/异常的区别有一定的认识。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Laravel 8 错误处理是一个关键部分,它确保了应用程序在遇到错误时能够优雅地处理,提供有用的反馈给用户,同时还能记录详细的错误日志供开发者诊断。以下是 Laravel 8 错误处理的主要方面: 1. **异常处理器(ExceptionHandler)**:Laravel 提供了一个全局的 `App\Exceptions\Handler` 类,用于捕获和处理所有的应用级异常。你可以在这里自定义错误视图、决定是否显示给用户、记录错误等。 2. **间件(Middleware)**:Laravel 使用间件来处理 HTTP 请求。例如,`render()` 间件会将未处理的异常转化为 HTTP 响应,提供友好的错误页面。 3. **日志记录(Logging)**:Laravel 默认使用 Monolog 库进行错误日志记录,可以通过 `config/app.php` 配置文件调整日志级别和存储位置。`error.log` 文件通常记录详细的错误信息。 4. **自定义错误页面(Custom Error Pages)**:Laravel 提供了 `resources/views/errors` 文件夹,你可以创建不同的错误页面模板,比如 404 错误、500 错误等。 5. **HTTP 错误代码(HTTP Status Codes)**:Laravel 使用预定义的 HTTP 状态码来响应请求,如 404(未找到)、500(服务器内部错误)等。这些状态码可以自定义或重定向。 6. **异常监听器(Event Listeners)**:通过监听 `Illuminate\Events\ErrorException` 或者自定义事件,可以在特定错误发生时执行额外的操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cookcyq

请作者喝杯暖暖的奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值