thinkphp笔记-异常处理、日志处理
异常处理
系统输出的异常信息比PHP 原生的要人性化的多,但需要开启调试模式;
如果你想更改异常页面的样式、布局之类的,可以修改这个页面:
vendor/topthink/framework/src/tpl/think_exception.tpl
如果你想要直接替换掉异常页面,换成别的,可以在config/app.php 中进行设置:
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
app()->getThinkPath() 这个是一个助手函数,更多的助手函数在
\vendor\topthink\framework\src\think\App.php 文件中
其中有getBasePath()、getAppPath()等等,需要从源码中自己发掘。
系统的异常抛出是自动进行的,并不需要你手动抛出,但也支持手动;
try {
// 使用助手函数,直接放一个验证类进去
validate(User::class)
->batch(true)
->scene('edit') // 写入场景规则,不验证邮箱
->check([
'name' => '',
'price' => '',
'email' => 'xiaoxin163.com'
]);
} catch(ValidateException $e) {
// 手动抛出异常
throw new Exception('异常', 10086);
}
我们可以使用try...catch 对可能发生的异常进行手动捕获或抛出;
我们可以抛出HTTP 异常,所谓HTTP 异常比如404 错误,500 错误之类;
try {
...
} catch() {
// 好处就是可以设置状态码 从而跳转页面
throw new HttpException(404, '错误信息');
}
需要引入
use think\exception\HttpException;
或者使用助手函数,系统提供了一个助手函数abort()方法简化HTTP 异常抛出;实现的效果相同
try {
...
} catch() {
// 好处就是可以设置状态码 从而跳转页面
// throw new HttpException(404, '错误信息');
abort(404, '错误信息');
}
如果系统关闭了调试模式,进入部署环境下,可以设置HTTP 错误页面,比如404;
APP_DEBUG = false
然后在config/app.php中,在末尾添加404时跳转属性
<?php
// +----------------------------------------------------------------------
// | 应用设置
// +----------------------------------------------------------------------
return [
// 应用地址
'app_host' => env('app.host', ''),
// 异常页面的模板文件
'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl',
// 显示错误信息
'show_error_msg' => true,
...
// 下面这个为新增
'http_exception_template' => [
// 定义404 错误的模板文件地址
404 => \think\facade\App::getAppPath() . '404.html',
]
];
其中,\think\facade\App::getAppPath()与app()->getThinkPath()都是使用的\vendor\topthink\framework\src\think\App.php文件中的方法,区别仅仅是调用方式的不同。
日志处理
日志处理的操作由Log 类完成,它记录着所有程序中运行的错误记录;配置文件在config/log.php,在其中可以配置日志写入的方式。
日志是写入磁盘中的,是文本文件。所以这些文件存放在
\runtime\log\202407\01.log
开启调试模式后,.env中APP_DEBUG=true,会记录错误在哪一行。
use think\facade\Log;
Log::record('测试日志');
然后找到最新的日志文件,可以看到文件中新增了一行
[2024-07-02T08:22:14+08:00][info] 测试日志
系统提供了不同日志级别,默认info 级别,从低到高排列如下:
debug/info/notice/warning/error/critical/alert/emergency/sql;
一般记录就是info 信息,我们也可以指定我们的信息级别;
Log::record('错误日志!', 'error');
[2024-07-02T08:24:52+08:00][error]错误日志
record()方法不是实时记录,需要等待程序完毕后决定是否写入日志;
如果在写入方法后添加close()关闭写入,那么record()方法则不写入;
Log::record('cuowu日志', 'error');
Log::close();
如此,那么记录的错误日志则不会写入。
系统还提供了一个write()方法,进行时时写入,不理会其它限制;
Log::write('错误日志', 'error');
Log::close();
使用write那么,无论是否使用close,都会写入到日志中。
系统发生异常后,会自动写入error 日志,如果你想手动也可以;
try {
echo 0/0;
} catch (ErrorException $e)
{
echo '发生错误:'.$e->getMessage();
Log::record('被除数不得为零', 'error');
}
当使用try-catch捕获到错误的时候,默认是不写入日志的,因此如果在try中写入日志就需要手动操作。
还可以写入错误码
try {
echo 0/0;
} catch (ErrorException $e)
{
echo '发生错误:'.$e->getMessage();
Log::record('[' . $e->getCode() . ']被除数不得为零', 'error');
}
对于各种日志级别,系统提供了一些快捷方式和助手函数,比如
Log::error('错误日志!'); //等价于 Log::record('错误日志!', 'error')
Log::info('信息日志!'); //等价于 Log::record('信息日志!', 'info')
trace('错误日志!', 'error');
trace('信息日志!', 'info');
系统默认并不记录HTTP 异常,因为这种异常容易遭受攻击不断写入日志;
除了系统提供的几种类型,也可以自己定义日志类型;
Log::diy('自定义日志');
[2024-07-02T08:37:16+08:00][diy] 自定义日志
在配置文件config/log.php 中,可以设置限定日志文件的级别,不属于的无法写入;
'level' => ['error','info'], // 只能写入error 和info 其他的不能写入日志
在配置文件log.php 中,添加转换为json 格式(方便处理,以便于展示在页面中);
<?php
return [
...
// 日志通道列表
'channels' => [
'file' => [
...
// 使用JSON格式记录
'json' => true,
...
],
// 其它日志通道配置
],
];
设置后,再写入的日志就会变成如下形式
[2024-07-02T08:35:08+08:00][error] [2]Division by zero[D:\phpstudy\phpstudy_pro\WWW\xuexi\tp6\app\controller\Store.php:101]
// 上面是设置之前,下面是设置json之后
{"time":"2024-07-02T08:40:57+08:00","type":"diy","msg":"自定义日志"}
{"time":"2024-07-02T08:40:58+08:00","type":"diy","msg":"自定义日志"}
使用::getLog()方法,可以获取写入到内存中的日志;
Log::record('错误日志', 'error');
dump(Log::getLog());
Log::record会在执行之后才会写入日志,而日志信息会存放在内存中,使用Log::getLog()方法会在日志还没写入文件的时候,提前先从内存中获取到将要写入日志的信息。
array:1 [
"error" => array:1 [
0 => "错误日志"
]
]
但是如果使用Log::write那么,使用getLog就只能获取到一个空数组
Log::write('错误日志', 'error');
dump(Log::getLog()); // []
record原理是先将日志写入内存中,待执行完毕后看看代码有无问题,有问题则写入到日志文件中,因此可以用getLog从内存中将错误信息拉出来;
write是直接写入到日志文件中的,不经过内存,所以无法使用getLog获取到。
使用::clear()方法,可以清理掉内存中的日志;
Log::record('错误日志', 'error');
Log::clear();
dump(Log::getLog());
比如上面代码,1、record先将日志写入内存;2、clear()从内存中将预写的日志删除掉;3、getLog()则无法从内存中获取预写入的日志,因此打印出来的就是空数组;4、同样的,日志文件中也不会写入任何内容,因为在内存阶段都被清除掉了。
在配置文件config/log.php 中,可以设置以单独文件存储的方式(就是永远都只有一个文件);
'single' => true,
如此设置后,会在目录下新建:runtime\log\single.log文件。以后会将所有日志都记录在这个文件中。当然建议不要这么做。