# 快速入门(八):调试和日志
项目开发的时候,出现错误在所难免,最大的困惑在于发现问题所在,其次才是如何解决问题。因此懂得如何调试和跟踪问题非常之关键,`5.0`版本提供了非常方便的调试工具和手段,让你更容易定位和发现问题。
本篇授你`TP5`调试大法之独门五式,稍加修炼,则可让你的TP5调试功力独步天下。
- - [第一式:未雨绸缪——页面Trace](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/192760#-trace)
- [第二式:初见端倪——异常页面](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/192760#--1)
- [第三式:拨云见日——断点调试](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/192760#--2)
- [第四式:欲穷千里——日志分析](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/192760#--3)
- [第五式:运筹帷幄——远程调试](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/192760#--4)
## 第一式:未雨绸缪——页面Trace
> 第一式是基本式,简单易学,但往往容易被忽视。
> 难度系数:0
> 实用指数:6
页面`Trace`是`ThinkPHP`经典的调试手段,`ThinkPHP5.0`继续发扬光大,已经可以支持不依赖页面显示。
页面`Trace`的主要作用包括:
- 查看运行数据;
- 查看文件加载情况;
- 查看运行流程;
- 查看当前执行SQL;
- 跟踪调试数据;
- 查看页面错误信息;
系统默认不开启页面`Trace`,开启页面`Trace`是在应用配置文件中设置下面的参数:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 开启应用Trace调试</span><span class="hljs-string">'app_trace'</span> => <span class="hljs-keyword">true</span>,
<span class="hljs-comment">// 设置Trace显示方式</span><span class="hljs-string">'trace'</span> => [
<span class="hljs-comment">// 在当前Html页面显示Trace信息</span><span class="hljs-string">'type'</span> => <span class="hljs-string">'html'</span>,
],
```
```
我们用默认自带的欢迎页面来测试,访问后就可以看到页面`Trace`信息按钮。
![](https://img.kancloud.cn/20/b4/20b4420943643b4e4ddff4238f85ad3b_807x551.png)
注意看在右下角可以看到一个`ThinkPHP`的`LOGO`和当前页面的运行时间, ![](https://img.kancloud.cn/e0/3d/e03d0be3c1830843e598e83e4279a6bc_107x31.png) 点击会弹出详细的`Trace`信息,如图:
![](https://img.kancloud.cn/02/d2/02d23c285b8559dd85be8f349fe25651_588x174.png)
这是系统默认的`Trace`信息显示效果,包含了基本、文件、流程、错误、`SQL`和调试信息。
**基本信息**一栏显示了当前请求的运行信息,包括运行时间、吞吐率、内存开销和文件加载等基本信息,通过这个页面可以对当前的请求有一个直观的了解,例如当前请求的内存开销是否过大,查询次数是否在合理的范围之内等等。
**文件信息**一栏则按加载顺序显示了当前请求加载的文件列表。
**流程信息**一栏则会显示当前请求做了哪些操作,大家可以在开发的过程中经常关注下不同页面的请求和区别,该栏的内容开启调试模式后可见。
**错误信息**一栏会显示页面执行过程中的相关错误,包括警告错误(由于ThinkPHP5.0默认情况下对错误零容忍,所以你在正常情况下基本看不到任何错误,因为有任何错误都会直接抛出异常)。
如果你当前请求使用了数据库操作和查询的话,并且开启了数据库调试模式(注意,数据库调试模式可以单独开启,在数据库配置文件中配置开启`debug`参数)会在`SQL`一栏显示相关的`SQL`连接和查询信息,如图:
![](https://img.kancloud.cn/a3/8f/a38f5da08899782f7471caf31d66c628_629x183.png)
对于一些性能不高的查询尤其要引起注意,及早进行优化,如果要查看每个`SQL`查询的`EXPLAIN`信息,可以在数据库配置文件中设置`sql_explain`参数如下:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 是否需要进行SQL性能分析</span><span class="hljs-string">'sql_explain'</span> => <span class="hljs-keyword">true</span>,
```
```
开启后,我们就可以看到SQL语句的下面增加了`EXPLAIN`分析信息:
![](https://img.kancloud.cn/ab/cd/abcdbe724f89ab726fe2a52201867504_839x182.png)
最后一栏是用于开发过程的调试输出,使用`trace`方法调试输出的信息不会在页面直接显示,而是在页面`Trace`的调试一栏显示输出。
我们在控制器的方法中增加
```
<pre class="calibre18">
```
trace(<span class="hljs-string">'这是测试调试信息'</span>);
trace([<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]);
```
```
然后刷新页面会看到:
![](https://img.kancloud.cn/d4/0a/d40a681a5c8c5cd1748380c656e12faf_356x119.png)
如果你不希望影响页面的输出效果,可以启用浏览器Trace调试信息,设置如下:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 开启应用Trace调试</span><span class="hljs-string">'app_trace'</span> => <span class="hljs-keyword">true</span>,
<span class="hljs-comment">// 设置Trace显示方式</span><span class="hljs-string">'trace'</span> => [
<span class="hljs-comment">// 使用浏览器console显示页面trace信息</span><span class="hljs-string">'type'</span> => <span class="hljs-string">'console'</span>,
],
```
```
设置后,用`Chrome`浏览器打开控制台切换到`console`可以看到如下显示:
![](https://img.kancloud.cn/67/cd/67cd2d876be13923f1306f8ac569b216_876x634.png)
控制台方式依然可以查看基本、文件、流程、错误、SQL和调试栏的相关信息。
并且支持颜色显示,例如:
![](https://img.kancloud.cn/aa/e2/aae276dbe680a269cfa711b2486d000a_696x299.png)
现在你已经基本了解了页面`Trace`的作用了,在开发过程中,开启页面`Trace`显示可以让你及早了解系统运行状况和及时排查隐患,起到未雨绸缪的作用。
> Ajax方式请求的信息不会在页面Trace中显示,还包括部分页面Trace之后执行的日志信息也无法在Trace中查看到。
## 第二式:初见端倪——异常页面
> 第二式是临危式,一旦遇“敌”方出此招,必须有波澜不惊的气势方能驾驭自如。
> 难度系数:3
> 实用指数:8
前面已经提到,`ThinkPHP5.0`对错误非常严谨,默认情况下,任何的错误(包括警告错误)系统都会抛出异常。
为了培养实战经验,让我们来和异常进行一次亲密接触吧,下面的代码用了一个未定义索引`$_GET['name']`:
```
<pre class="calibre18">
```
<span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>;
<span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span></span>{
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-number">()</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'hello,'</span>.<span class="hljs-regexp">$_GET</span>[<span class="hljs-string">'name'</span>];
}
}
```
```
访问 `http://tp5.com` 后显示:
![](https://img.kancloud.cn/56/3e/563e332ba213df5e899650b935dd4304_777x542.png)
如果你的系统是英文的话,会自动显示英文提示:
![](https://img.kancloud.cn/cb/e1/cbe15cbc00e585b561fbdc4a5598d0a7_781x550.png)
异常页面除了显示错误信息之外,还有很多的额外的信息能够帮助你快速定位和发现问题所在。
第一步是查看异常所在的文件源码,错误行会用红色标识,如果要继续一探究竟,那么就需要查看下面的`Call Stack`信息,这个是显示了当前异常的详细Trace信息,带下划线样式的地方,鼠标移上去会停留会显示该文件的详细位置
![](https://img.kancloud.cn/16/ac/16ac395f33455c05c554dc6eadd24f53_464x164.png)
这些信息还不够,不要急,仔细查看完整的异常页面,其实还包含了当前请求的全局变量和常量,如图:
![](https://img.kancloud.cn/20/40/204060daf82546483e1d4a06c4193819_827x2229.png)
遇到异常页面后要沉着冷静的分析错误信息,根据经验,第二式可以解决80%的问题定位,调试大神一般会在这个阶段把问题找出。
如若仍然无从下手的,请继续修炼第三式。
## 第三式:拨云见日——断点调试
> 第三式为破敌式,不断设置断点缩小和定位错误范围,直到找到错误位置。虽然简单粗暴,但对于复杂的情况下排查错误非常实用,并且如何设置断点有很多的经验。
> 难度系数:6
> 实用指数:9
系统为断点调试提供了几个有用的方法,诀窍就是通过调试信息不断缩小问题的范围以及诊断变量的变化。
### `dump` 变量调试输出
在你需要的断点位置,调用`dump`方法,可以输出浏览器友好的变量信息,支持任何变量类型,例如:
```
<pre class="calibre18">
```
<span class="hljs-keyword">dump</span>(<span class="hljs-string">'测试'</span>);
<span class="hljs-keyword">dump</span>([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]);
<span class="hljs-keyword">dump</span>(User::get());
```
```
页面会输出类似下面的信息:
![](https://img.kancloud.cn/18/7f/187f4006ce191cf2c72f3c49aae00d6e_516x623.png)
### `halt` 变量调试并中断输出
`halt`方法的作用和`dump`一样,只是在输出变量之后会中断当前程序的执行,下面是示例代码:
```
<pre class="calibre18">
```
<span class="hljs-keyword">dump</span>(<span class="hljs-string">'测试'</span>);
halt([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]);
halt(<span class="hljs-string">'这里的信息是不会输出的'</span>);
```
```
页面会输出:
```
<pre class="calibre18">
```
E:\www\tp\thinkphp\<span class="hljs-keyword">library</span>\think\Debug.php:<span class="hljs-number">168</span>:<span class="hljs-keyword">string</span> <span class="hljs-string">'测试'</span> (length=<span class="hljs-number">6</span>)
E:\www\tp\thinkphp\<span class="hljs-keyword">library</span>\think\Debug.php:<span class="hljs-number">168</span>:
<span class="hljs-keyword">array</span> (size=<span class="hljs-number">3</span>)
<span class="hljs-number">0</span> => <span class="hljs-keyword">string</span> <span class="hljs-string">'a'</span> (length=<span class="hljs-number">1</span>)
<span class="hljs-number">1</span> => <span class="hljs-keyword">string</span> <span class="hljs-string">'b'</span> (length=<span class="hljs-number">1</span>)
<span class="hljs-number">2</span> => <span class="hljs-keyword">string</span> <span class="hljs-string">'c'</span> (length=<span class="hljs-number">1</span>)
```
```
第二个`halt`方法不会被执行,因为`halt`方法在执行后就中止程序了。
### `trace` 控制台输出
如果你不希望在页面输出调试信息,可以使用`trace`方法,该方法输出的信息会在页面`Trace`或者浏览器`Console`中显示,使用方法和`dump`是一样的。
```
<pre class="calibre18">
```
trace(<span class="hljs-string">'测试'</span>);
trace([<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>]);
trace(<span class="hljs-string">User:</span>:get());
```
```
输出效果如图:
![](https://img.kancloud.cn/61/cf/61cfc0751249775cbb363f7ec9d86023_359x483.png)
利用好这三个调试方法,足以临场杀敌,百万“大军”中取`BUG`首级!
## 第四式:欲穷千里——日志分析
> 第四式为诊断式,意为经常追溯日志信息,协同分析错误原因。
> 难度系数:6
> 实用指数:7
系统记录的日志信息在很多时候能够发挥意想不到的作用,默认情况下,系统使用文件方式记录日志,并且按照日期自动分开子目录保存,文件结构如下:
```
<pre class="calibre18">
```
runtime/<span class="hljs-number">log</span>
└─<span class="hljs-number">201608</span><span class="hljs-number">05.l</span>og
<span class="hljs-number">06.l</span>og
<span class="hljs-number">08.l</span>og
<span class="hljs-number">09.l</span>og
<span class="hljs-number">10.l</span>og
<span class="hljs-number">11.l</span>og
<span class="hljs-number">12.l</span>og
```
```
每天会生成一个当天的日志文件,日志文件的内容和页面`Trace`信息的内容类似,但区别在于所有的请求都会记录,因此日志信息包含了大量的信息,更加有利于我们分析问题。
ThinkPHP对系统的日志按照级别来分类,并且这个日志级别完全可以自己定义,系统内部使用的级别包括:
- **log** 常规日志,用于记录日志
- **error** 错误,一般会导致程序的终止
- **notice** 警告,程序可以运行但是还不够完美的错误
- **info** 信息,程序输出信息
- **debug** 调试,用于调试信息
- **sql** SQL语句,用于SQL记录,只在数据库的调试模式开启时有效
系统提供了不同日志级别的快速记录方法,例如:
```
<pre class="calibre18">
```
<span class="hljs-operator"><span class="hljs-title1">Log</span>:<span class="hljs-string">:<span class="hljs-function">error</span>(<span class="hljs-operator">'错误信息'</span>)</span></span>;
<span class="hljs-operator"><span class="hljs-title1">Log</span>:<span class="hljs-string">:<span class="hljs-function">info</span>(<span class="hljs-operator">'日志信息'</span>)</span></span>;
```
```
或者使用`trace`方法记录日志
```
<pre class="calibre18">
```
trace(<span class="hljs-string">'错误信息'</span>,<span class="hljs-string">'error'</span>);
trace(<span class="hljs-string">'日志信息'</span>,<span class="hljs-string">'info'</span>);
```
```
为了便于分析,还支持设置某些级别的日志信息单独文件记录,例如:
```
<pre class="calibre18">
```
<span class="hljs-string">'log'</span> => [
<span class="hljs-string">'type'</span> => <span class="hljs-string">'file'</span>,
<span class="hljs-comment">// error和sql日志单独记录</span><span class="hljs-string">'apart_level'</span> => [<span class="hljs-string">'error'</span>,<span class="hljs-string">'sql'</span>],
],
```
```
设置后,就会单独生成`error` 和 `sql`两个类型的日志文件,主日志文件中将不再包含这两个级别的日志信息,日志文件结构类似于:
```
<pre class="calibre18">
```
runtime/<span class="hljs-number">log</span>
└─<span class="hljs-number">201608</span><span class="hljs-number">05.l</span>og
<span class="hljs-number">06.l</span>og
<span class="hljs-number">08.l</span>og
<span class="hljs-number">09.l</span>og
<span class="hljs-number">10.l</span>og
<span class="hljs-number">11.l</span>og
<span class="hljs-number">12.l</span>og
<span class="hljs-number">12</span>_error.<span class="hljs-number">log</span><span class="hljs-number">12</span>_sql.<span class="hljs-number">log</span>
```
```
定期查看系统的日志文件便于及时发现一些可能存在的隐患,以及给已有的问题提供更多的参考依据。
日志文件可以使用`Socket`方式记录到远程服务器,这就是后面要讲的远程调试功能,当然,你还可以扩展自己的日志记录方式来满足更多的要求。
## 第五式:运筹帷幄——远程调试
> 第五式为独步式,一旦修炼完成,千里之外任何错误尽在掌握。
> 难度系数:6
> 实用指数:8
远程调试功能暂且不表,我们将会在下一章`API`开发中为你详细讲述。
勤加修炼并掌握好这`ThinkPHP5.0`的五式调试大法,任何错误都会被你秒破!
- 脕茫隆垄脨貌脩脭
- 脕茫隆垄脨貌脩脭
- 脪禄隆垄禄霉麓隆
- 脪禄隆垄禄霉麓隆
- 露镁隆垄URL潞脥脗路脫脡
- 露镁隆垄URL潞脥脗路脫脡
- 脠媒隆垄脟毛脟贸潞脥脧矛脫娄
- 脠媒隆垄脟毛脟贸潞脥脧矛脫娄
- 脣脛隆垄脢媒戮脻驴芒
- 脣脛隆垄脢媒戮脻驴芒
- 脦氓隆垄虏茅脩炉脫茂脩脭
- 脦氓隆垄虏茅脩炉脫茂脩脭
- 脕霉隆垄脛拢脨脥潞脥鹿脴脕陋
- 拢篓1拢漏脛拢脨脥露篓脪氓
- 拢篓2拢漏禄霉麓隆虏脵脳梅
- 拢篓3拢漏露脕脠隆脝梅潞脥脨脼赂脛脝梅
- 拢篓4拢漏脌脿脨脥脳陋禄禄潞脥脳脭露炉脥锚鲁脡
- 拢篓5拢漏虏茅脩炉路露脦搂
- 拢篓6拢漏脢盲脠毛潞脥脩茅脰陇
- 拢篓7拢漏鹿脴脕陋
- 拢篓8拢漏脛拢脨脥脢盲鲁枚
- 脝脽隆垄脢脫脥录潞脥脛拢掳氓
- 脝脽隆垄脢脫脥录潞脥脛拢掳氓
- 掳脣隆垄碌梅脢脭潞脥脠脮脰戮
- 掳脣隆垄碌梅脢脭潞脥脠脮脰戮
- 戮脜隆垄API驴陋路垄
- 戮脜隆垄API驴陋路垄
- 脢庐隆垄脙眉脕卯脨脨鹿陇戮脽
- 脢庐隆垄脙眉脕卯脨脨鹿陇戮脽
- 脢庐脪禄隆垄脌漏脮鹿
- 脢庐脪禄隆垄脌漏脮鹿
- 脢庐露镁隆垄脭脫脧卯
- Cookie
- Session
- 碌楼脭陋虏芒脢脭
- 脥录脧帽麓娄脌铆
- 脦脛录镁脡脧麓芦
- 脩茅脰陇脗毛
- 赂陆脗录
- A隆垄鲁拢录没脦脢脤芒录炉
- B隆垄3.2潞脥5.0脟酶卤冒
- C隆垄脰煤脢脰潞炉脢媒
- 路卢脥芒脝陋拢潞脩搂脧掳ThinkPHP5碌脛脮媒脠路脳脣脢脝
- 路卢脥芒脝陋拢潞脩搂脧掳ThinkPHP5碌脛脮媒脠路脳脣脢脝