本篇我們來全面了解下如何在ThinkPHP開發(fā)過程中進(jìn)行調(diào)試工作。
調(diào)試模式
說到調(diào)試,我們可能第一個想到的就是調(diào)試模式,沒錯,ThinkPHP也有專門為開發(fā)過程而設(shè)置的調(diào)試模式,ThinkPHP的調(diào)試模式與眾不同,會犧牲一定的執(zhí)行效率,但帶來的方便和除錯功能非常值得。 我們強烈建議ThinkPHP開發(fā)人員在開發(fā)階段始終開啟調(diào)試模式(直到正式部署后關(guān)閉調(diào)試模式),方便及時發(fā)現(xiàn)隱患問題和分析、解決問題。[-more-]
開啟調(diào)試模式很簡單,只需要在入口文件中增加一行常量定義代碼:
<?php
//開啟調(diào)試模式
define('APP_DEBUG', true);
//加載框架入口文件
require './ThinkPHP/ThinkPHP.php';
在完成開發(fā)階段部署到生產(chǎn)環(huán)境后,只需要刪除調(diào)試模式定義代碼即可切換到部署模式。 調(diào)試模式的優(yōu)勢在于:
- 開啟日志記錄,任何錯誤信息和調(diào)試信息都會詳細(xì)記錄,便于調(diào)試;
- 關(guān)閉模板緩存,模板修改可以即時生效;
- 記錄SQL日志,方便分析SQL;
- 關(guān)閉字段緩存,數(shù)據(jù)表字段修改不受緩存影響;
- 嚴(yán)格檢查文件大小寫(即使是Windows平臺),幫助你提前發(fā)現(xiàn)Linux部署問題;
- 可以方便用于開發(fā)過程的不同階段,包括開發(fā)、測試和演示等任何需要的情況,不同的應(yīng)用模式可以配置獨立的項目配置文件;
在開啟調(diào)試模式的狀態(tài)下,我們可以給項目設(shè)置不同的應(yīng)用狀態(tài),并加載不同的項目配置文件,但是無論如何,都會首先導(dǎo)入框架默認(rèn)的調(diào)試模式配置文件,該文件位于系統(tǒng)目錄的Confdebug.php。
通常情況下,調(diào)試配置文件里面可以進(jìn)行一些開發(fā)模式所需要的配置。例如,配置額外的數(shù)據(jù)庫連接用于調(diào)試,開啟日志寫入便于查找錯誤信息、開啟頁面Trace輸出更多的調(diào)試信息等等。
如果沒有配置應(yīng)用狀態(tài),系統(tǒng)默認(rèn)則默認(rèn)為debug狀態(tài),也就是說默認(rèn)的配置參數(shù)是:
'APP_STATUS' => 'debug', //應(yīng)用調(diào)試模式狀態(tài)
如果檢測到項目的配置目錄中有存在debug.php文件,則會自動加載該配置文件,并且和系統(tǒng)項目配置文件以及系統(tǒng)調(diào)試配置文件合并,也就是說,debug.php配置文件只需要配置和項目配置文件以及系統(tǒng)調(diào)試配置文件不同的參數(shù)或者新增的參數(shù)。 如果想在調(diào)試模式下面增加應(yīng)用狀態(tài),例如測試狀態(tài),則可以在項目配置文件中改變設(shè)置如下:
'APP_STATUS' => 'test', //應(yīng)用調(diào)試模式狀態(tài)
這樣的話,系統(tǒng)會自動嘗試加載項目配置目錄下面的test.php 配置文件,可以在test配置文件中改變相關(guān)設(shè)置,例如改變測試數(shù)據(jù)庫的連接信息等等。
由于調(diào)試模式?jīng)]有任何緩存,因此涉及到較多的文件IO操作和模板實時編譯,所以在開啟調(diào)試模式的情況下,性能會有一定的下降,但不會影響部署模式的性能。另外需要注意的是,一旦關(guān)閉調(diào)試模式,項目的調(diào)試配置文件即刻失效。
頁面Trace
調(diào)試模式并不能完全滿足我們調(diào)試的需要,有時候我們需要手動的輸出一些調(diào)試信息。除了本身可以借助一些開發(fā)工具進(jìn)行調(diào)試外,ThinkPHP還提供了一些內(nèi)置的調(diào)試工具和函數(shù)。例如,頁面Trace功能就是ThinkPHP提供給開發(fā)人員的一個用于開發(fā)調(diào)試的輔助工具。可以實時顯示當(dāng)前頁面的操作的請求信息、運行情況、SQL執(zhí)行、錯誤提示等,并支持自定義顯示。 頁面Trace功能對調(diào)試模式和部署模式都有效,不過只能用于有頁面輸出的情況(如果你的操作沒有任何輸出,那么可能頁面Trace功能對你幫助不大,你可能需要使用后面的調(diào)試方法)。但是在部署模式下面,顯示的調(diào)試信息沒有調(diào)試模式完整,通常我們建議頁面Trace配合調(diào)試模式一起使用。
要開啟頁面Trace功能,需要在項目配置文件中設(shè)置:
'SHOW_PAGE_TRACE' =>true, // 顯示頁面Trace信息
該參數(shù)默認(rèn)為關(guān)閉,開啟后并且你的頁面有模板輸出的話,頁面右下角會顯示ThinkPHP的LOGO:

我們看到的LOGO后面的數(shù)字就是當(dāng)前頁面的執(zhí)行時間(單位是秒) 點擊該圖標(biāo)后,會展開詳細(xì)的頁面Trace信息,如圖:

頁面Trace框架有6個選項卡,分別是基本、文件、流程、錯誤、SQL和調(diào)試,點擊不同的選項卡會切換到不同的Trace信息窗口。
基本:當(dāng)前頁面的基本摘要信息,例如執(zhí)行時間、內(nèi)存開銷、文件加載數(shù)、查詢次數(shù)等等。
文件:詳細(xì)列出當(dāng)前頁面執(zhí)行過程中加載的文件及其大小。
流程:會列出當(dāng)前頁面執(zhí)行到的行為和相關(guān)流程(待完善)。
錯誤:當(dāng)前頁面執(zhí)行過程中的一些錯誤信息,包括警告錯誤。
SQL:當(dāng)前頁面執(zhí)行到的SQL語句信息。
調(diào)試:開發(fā)人員在程序中進(jìn)行的調(diào)試輸出。
頁面Trace的選項卡是可以定制和擴展的,默認(rèn)的配置為:
'TRACE_PAGE_TABS'=>array(
'base'=>'基本',
'file'=>'文件',
'think'=>'流程',
'error'=>'錯誤',
'sql'=>'SQL',
'debug'=>'調(diào)試'
)
也就是我們看到的默認(rèn)情況下顯示的選項卡,如果你希望增加新的選項卡:用戶,則可以修改配置如下:
'TRACE_PAGE_TABS'=>array(
'base'=>'基本',
'file'=>'文件',
'think'=>'流程',
'error'=>'錯誤',
'sql'=>'SQL',
'debug'=>'調(diào)試',
'user'=>'用戶'
)
也可以把某幾個選項卡合并,例如:
'TRACE_PAGE_TABS'=>array(
'base'=>'基本',
'file'=>'文件',
'think'=>'流程',
'error|debug|sql'=>'調(diào)試',
'user'=>'用戶'
)
我們把剛才的用戶信息調(diào)試輸出到用戶選項卡,trace方法的用法如下:
trace($user,'用戶信息','user');
第三個參數(shù)表示選項卡的標(biāo)識,和我們在TRACE_PAGE_TABS中配置的對應(yīng)。
默認(rèn)情況下,頁面Trace窗口顯示的信息是不會保存的,如果希望保存這些trace信息,我們可以配置PAGE_TRACE_SAVE參數(shù):
'PAGE_TRACE_SAVE'=>true
開啟頁面trace信息保存后,每次的頁面Trace信息會以日志形式保存到項目的日志目錄中,命名格式是: 當(dāng)前日期_trace.log,例如:
12-06-21_trace.log
如果不希望保存所有的選項卡的信息,可以設(shè)置需要保存的選項卡,例如:
'PAGE_TRACE_SAVE'=>array('base','file','sql');
設(shè)置后只會保存base、file和sql三個選項卡的信息。
Trace方法
頁面Trace只能用于有頁面輸出的情況,但是trace方法可以用在任何情況,而且trace方法可以用于AJAX等操作。
Trace方法的格式: trace('變量','標(biāo)簽','級別','是否記錄日志') 例如:
$info = '測試信息';
trace($info,'提示');
如果希望把變量調(diào)試輸出到頁面Trace的某個選項卡里面,可以使用:
trace($info,'提示','user');
表示輸出到user選項卡,如果沒有指定選項卡的話,默認(rèn)會輸出到debug選項卡。
trace方法也可以直接拋出異常,如果是輸出到ERR選項卡,并且開啟
'TRACE_EXCEPTION'=>true
的話,
trace($info,'錯誤','ERR');
會拋出異常。
有三種情況下,trace方法會記錄日志:
- AJAX請求
- SHOW_PAGE_TRACE為false,也就是頁面Trace關(guān)閉的情況下
- trace方法的第四個參數(shù)為true
在這種情況下,trace方法的第三個參數(shù)就表示記錄的日志級別,通常包括:
'ERR' // 一般錯誤: 一般性錯誤
'WARN' // 警告性錯誤: 需要發(fā)出警告的錯誤
'NOTIC' // 通知: 程序可以運行但是還不夠完美的錯誤
'INFO' // 信息: 程序輸出信息
'DEBUG' // 調(diào)試: 調(diào)試信息
'SQL' // SQL:SQL語句
變量調(diào)試
輸出某個變量是開發(fā)過程中經(jīng)常會用到的調(diào)試方法,除了使用php內(nèi)置的var_dump和print_r之外,ThinkPHP框架內(nèi)置了一個對瀏覽器友好的var_dump方法,用于輸出變量的信息到瀏覽器查看。
dump 瀏覽器友好的變量輸出
用法 dump($var, $echo=true, $label=null, $strict=true)
參數(shù) var(必須):要輸出的變量,支持所有變量類型
echo(可選):是否直接輸出,默認(rèn)為true,如果為false則返回但不輸出
label(可選):變量輸出的label標(biāo)識,默認(rèn)為空
strict(可選):輸出變量類型,默認(rèn)為true,如果為false則采用print_r輸出
返回值 如果echo參數(shù)為false 則返回要輸出的字符串
使用示例:
$Blog = D("Blog");
$blog = $Blog->find(3);
dump($blog);
在瀏覽器輸出的結(jié)果是:
array(12) {
["id"] => string(1) "3"
["name"] => string(0) ""
["user_id"] => string(1) "0"
["cate_id"] => string(1) "0"
["title"] => string(4) "test"
["content"] => string(4) "test"
["create_time"] => string(1) "0"
["update_time"] => string(1) "0"
["status"] => string(1) "0"
["read_count"] => string(1) "0"
["comment_count"] => string(1) "0"
["tags"] => string(0) ""
}
性能調(diào)試
開發(fā)過程中,有些時候為了測試性能,經(jīng)常需要調(diào)試某段代碼的運行時間或者內(nèi)存占用開銷,系統(tǒng)提供了G方法可以很方便的獲取某個區(qū)間的運行時間和內(nèi)存占用情況。 例如:
G('begin');
// ...其他代碼段
G('end');
// ...也許這里還有其他代碼
// 進(jìn)行統(tǒng)計區(qū)間
echo G('begin','end').'s';
G('begin','end') 表示統(tǒng)計begin位置到end位置的執(zhí)行時間(單位是秒),begin必須是一個已經(jīng)標(biāo)記過的位置,如果這個時候end位置還沒被標(biāo)記過,則會自動把當(dāng)前位置標(biāo)記為end標(biāo)簽,輸出的結(jié)果類似于:
0.0056s
默認(rèn)的統(tǒng)計精度是小數(shù)點后4位,如果覺得這個統(tǒng)計精度不夠,還可以設(shè)置例如:
G('begin','end',6).'s';
可能的輸出會變成:
0.005587s
如果你的環(huán)境支持內(nèi)存占用統(tǒng)計的話,還可以使用G方法進(jìn)行區(qū)間內(nèi)存開銷統(tǒng)計(單位為kb),例如:
echo G('begin','end','m').'kb';
第三個參數(shù)使用m表示進(jìn)行內(nèi)存開銷統(tǒng)計,輸出的結(jié)果可能是:
625kb
同樣,如果end標(biāo)簽沒有被標(biāo)記的話,會自動把當(dāng)前位置先標(biāo)記位end標(biāo)簽。
如果環(huán)境不支持內(nèi)存統(tǒng)計,則該參數(shù)無效,仍然會進(jìn)行區(qū)間運行時間統(tǒng)計。
斷點調(diào)試
憑借強大的頁面Trace信息功能支持,ThinkPHP可以支持?jǐn)帱c調(diào)試功能。
我們只需要在不同的位置對某個變量進(jìn)行trace輸出即可,例如:
$blog = D("Blog");
$vo = $blog->create();
trace($vo,'create vo');
$vo = $blog->find();
trace($vo,'find vo');
錯誤調(diào)試
如果需要我們可以使用下面的方法輸出錯誤信息并中斷執(zhí)行:
halt($msg) //輸出錯誤信息,并中止執(zhí)行
模型調(diào)試
在模型操作中 ,為了更好的查明錯誤,經(jīng)常需要查看下最近使用的SQL語句,我們可以用getLastsql方法來輸出上次執(zhí)行的sql語句。例如:
$User = M("User"); // 實例化User對象
$User->find(1);
echo $User->getLastSql();
輸出結(jié)果是
SELECT * FROM think_user WHERE id = 1
并且每個模型都使用獨立的最后SQL記錄,互不干擾,但是可以用空模型的getLastSql方法獲取全局的最后SQL記錄。
$User = M("User"); // 實例化User模型
$Info = M("Info"); // 實例化Info模型
$User->find(1);
$Info->find(2);
echo M()->getLastSql();
echo $User->getLastSql();
echo $Info->getLastSql();
輸出結(jié)果是
SELECT * FROM think_info WHERE id = 2
SELECT * FROM think_user WHERE id = 1
SELECT * FROM think_info WHERE id = 2
getLastSql方法只能獲取最后執(zhí)行的sql記錄,如果需要了解更多的SQL日志,可以通過查看當(dāng)前的頁面Trace或者日志文件。
注意:Mongo數(shù)據(jù)庫驅(qū)動由于接口的特殊性,不存在執(zhí)行SQL的概念,因此SQL日志記錄功能是額外封裝實現(xiàn)的,所以出于性能考慮,只有在開啟調(diào)試模式的時候才支持使用getLastSql方法獲取最后執(zhí)行的SQL記錄。