接觸過php框架的朋友們可能都知道,紀錄檔在專案中的重要作用了,他可以幫助我們定位錯誤的位置,讓程式更友好(處理得當的話不會直接丟擲一大堆只有程式猿才真正動的英文),偵錯的時候也會很方便,還可以記錄一些重要的操作等等,總之一個完整的專案要是沒了紀錄檔系統,就已經開發的路上佈滿了荊棘、坑窪,肯定會磕磕絆絆的。
簡介
要掌握PHP紀錄檔系統,必須先對這幾點東西了解透徹。
一、php的幾個函數
set_exception_handler(callback $exception_handler); //異常捕獲自定義處理常式註冊 set_error_handler(callback $error_handler); //錯誤捕獲自定義處理常式註冊 register_shutdown_function(callback $callback); //程式執行時異常終止錯誤捕獲處理常式註冊
這三個函數在錯誤處理控制中給開發者提供了很大的自主空間,在紀錄檔系統中記錄紀錄檔資訊有他們的功勞。
在程式中出現異常(exception)問題時,php核心會丟擲異常錯誤,然後將錯誤資訊列印給使用者,如果註冊了exception處理常式,php丟擲的異常會轉給自定義的註冊的異常捕獲函數,這個函數裡面包含了我們要做的處理,記錄錯誤資訊(包括錯誤詳細內容、錯誤位置),該函數處理完異常後,異常就會終止。
當程式中出現error時,我們註冊的error處理常式會在函數中將錯誤資訊轉化為一個錯誤異常物件傳遞給例外處理函數,也就是第一步的$exception_handler函數。
當成續重出現shutdown錯誤時,會執行我們註冊的異常終止處理常式,該函數通過error_get_last()獲取到最後的shutdown時的錯誤物件,接著和上一部一樣,生成一個error exception物件,將該物件傳遞給我們註冊的例外處理函數。
可以看到,其實不管是異常還是錯誤,都是將自己的資訊轉化為例外處理函數認識的異常資訊,然後交給例外處理函數處理,非異常資訊就像化了妝的女人一樣,例外處理程式不認識這些非異常資訊,只有將裝卸掉(非異常資訊自己轉化為異常資訊,準確的說應該是丟擲),例外處理才認識。
php紀錄檔系統中的錯誤處理流程
那麼現在問題來了,這幾個函數一般會配合一個例外處理類庫,加上一個錯誤紀錄檔記錄類庫來進行工作,例外處理類庫中包含要註冊的3個函數,紀錄檔記錄類庫在$exception_handler中呼叫,用來合理的記錄和放置紀錄檔檔案的位置,上面說到的幾個函數一般是在程式框架入口處進行載入註冊的,就像下面這樣:
這裡面用的是array(class,function)這種方式。
set_exception_handler(array("Myexception","exceptionHandler")); set_error_handler(array("Myexception","errorHandler")); register_shutdown_function(array("Myexception","shutdownHandler"));
二、紀錄檔記錄相關類庫
第一部分介紹到的東西只是對異常、錯誤、shutdown進行了捕獲,這只是第一步,接下來還要對捕獲到的資訊進行合理的處理,比如說記錄這些紀錄檔資訊到本地檔案系統中(這個操作是在array(「Myexception」,」exceptionHandler」)),這個地方就用到了紀錄檔記錄類庫。(下面要說的類庫是借鑒了kohana紀錄檔系統的設計)。
日式紀錄檔記錄也很簡單只要做的將資訊新增到檔案末尾就行,這個很容易實現,相信大家都可以自己實現,但是要設計出一個便捷的、高效的、擴充套件的紀錄檔記錄類庫就不那麼簡單了,要經過長時間的實踐總結優化才可以,kohana框架中的紀錄檔記錄類庫已經比較成熟了,因此這裡拿來借鑒。
相信使用過kohana的使用者一定對kohana框架中的紀錄檔記錄比較熟悉,不熟悉也沒關係,我下面會大概的說說,在kohana原始碼中的application/bootstrap.php檔案中的第109——112行可以看到下面的程式碼:
/** * Attach the file write to logging. Multiple writers are supported. */ Kohana::$log->attach(new Log_File(APPPATH.'logs'));
這個就是新增一個紀錄檔記錄物件到紀錄檔物件中,注意橄欖色打底的倆個,他們是不同的類庫範例,在kohana中,紀錄檔記錄物件分為兩部分,第一部分就是紀錄檔物件,用來維護一個紀錄檔記錄物件的列表,這個要怎麼理解呢,其實就像一個容器,裡面包含了一個或多個紀錄檔記錄物件(這個就是第二部分,這些紀錄檔記錄物件才是真正來記錄紀錄檔的),還有每個物件要記錄的錯誤等級的陣列,當滿足錯誤等級的時候才會去記錄,不滿足就會略掉。下面是我自己簡化重新命名後的紀錄檔記錄方式:
self::$log = Log::instance(); self::$log->attach(new Logwriter("./data/debug"),Log::DEBUG); self::$log->attach(new Logwriter("./data/notice"),Log::NOTICE);
我這裡面為了更好地理解,將「容器」命名為Log,記錄的範例命名為Logwriter,可以看到我在程式入口處很容易的新增了兩不同的紀錄檔種類,第一個是記錄所有錯誤號比Log::DEBUG小的錯誤(錯誤級別比他高),並按規則記錄在資料夾./data/debug下面,第二個是記錄級別等於或高於Log::NOTICE的錯誤,當然了你還可以更詳細制定具體哪些錯誤好,傳遞陣列就行了,這個就是我感覺方便、快捷的地方,我們可以根據需求來新增錯誤紀錄檔、分不同的紀錄檔目錄,下面看一幅圖也許會有助於理解:
log與logwriter的關係
通過上面的圖你就會看到Log是一個容器,包含了具體的不同的logwriter物件,每個物件可能要記錄不同的資訊,當錯誤資訊要刷到檔案中的時候,會執行每一個Logwriter範例,看看自己是否要記錄errormessage中的錯誤,errormessage中的level不包含在Logwriter內時忽略。
這本分和第一部分怎麼合作的呢?
其實很簡單,當exception捕獲的異常時會呼叫新增一條錯誤資訊(包括錯誤位置、錯誤代號、錯誤資訊等資訊)到Log容器中的errormessage陣列中,然後當程式結束之後在將這些資訊寫入檔案,這裡還要注意下,也許你在閱讀kohana程式碼是發現沒有明顯的直接寫入到紀錄檔中去,這裡面kohana優化的比較好,因為php的一次執行可能出現多個錯誤,如果來一個錯誤你就去記錄一次這樣會在程式返回之前佔用多餘的io和時間,所以kohana的做法是預設將所有的錯誤、異常、紀錄檔存放在Log::$errormessage中,並在範例化的時候講Log中的writer操作註冊register_shutdown_function,這個函數的作用是在程式異常終止或者執行完成之後執行,前面第一部分也有使用到,這樣紀錄檔記錄就不會對本次php的執行產生帶大的影響。
推薦:《PHP培訓》
以上就是關於PHP框架中紀錄檔系統的詳解的詳細內容,更多請關注TW511.COM其它相關文章!