php異常處理

這篇文章主要對(duì)php中的錯(cuò)誤處理進(jìn)行簡(jiǎn)單的記錄

php一開(kāi)始被設(shè)計(jì)為一門面向過(guò)程的語(yǔ)言,所以異常處理沒(méi)有使用像Java一樣的 try / catch 機(jī)制值依,出錯(cuò)時(shí)直接顯示到頁(yè)面上圃泡,或者記錄到web服務(wù)器的錯(cuò)誤日志中,并且php的錯(cuò)誤分成了很多的級(jí)別愿险,例如E_ERROR颇蜡、E_WARNING、E_PARSE辆亏、E_NOTICE等等风秤,對(duì)于像E_ERROR、E_PARSE這樣的嚴(yán)重錯(cuò)誤扮叨,php會(huì)直接終止腳本的運(yùn)行缤弦。線下開(kāi)發(fā)時(shí),我們一般會(huì)設(shè)置error_reporting(-1)ini_set('display_errors', 'on')來(lái)報(bào)告并顯示所有異常彻磁,但是線上運(yùn)行的項(xiàng)目碍沐,出于安全的考慮,我們一般會(huì)隱藏錯(cuò)誤日志的頁(yè)面輸出衷蜓,如果php的配置文件中開(kāi)啟了log_error,那么相關(guān)的錯(cuò)誤日志可以在PHP的錯(cuò)誤日志中查詢累提,但是如果我們是多項(xiàng)目呢,通過(guò)PHP錯(cuò)誤日志來(lái)排錯(cuò)磁浇,顯然不科學(xué)斋陪,那么我們?nèi)绾蜗窨蚣苤幸粯觼?lái)優(yōu)雅的捕捉異常呢?相信有一定研發(fā)經(jīng)驗(yàn)的同學(xué)扯夭,一定聽(tīng)說(shuō)過(guò)或者用過(guò)大名鼎鼎的laravel框架鳍贾,那么它是如何處理異常的呢?通過(guò)閱讀源碼交洗,有興趣可以在Illuminate\Foundation\Bootstrap\HandleExceptions.php查看具體實(shí)現(xiàn)。這里只對(duì)其中的核心部分進(jìn)行分享橡淑,其中主要有三個(gè)PHP內(nèi)置函數(shù)的調(diào)用:set_error_handler构拳、set_exception_handler和register_shutdown_function

set_error_handler函數(shù)

set_error_handler來(lái)注冊(cè)自己的錯(cuò)誤處理方法來(lái)代替php的標(biāo)準(zhǔn)錯(cuò)誤處理方式(輸出到頁(yè)面或者記錄到日志),但是一些嚴(yán)重錯(cuò)誤是無(wú)法通過(guò)這種方式來(lái)處理的,具體我們來(lái)看手冊(cè)對(duì)該方法的介紹

mixed set_error_handler ( callable error_handler [, interror_types = E_ALL | E_STRICT ] )
設(shè)置一個(gè)用戶的函數(shù)(error_handler)來(lái)處理腳本中出現(xiàn)的錯(cuò)誤置森。
本函數(shù)可以用你自己定義的方式來(lái)處理運(yùn)行中的錯(cuò)誤斗埂, 例如,在應(yīng)用程序中嚴(yán)重錯(cuò)誤發(fā)生時(shí)凫海,或者在特定條件下觸發(fā)了一個(gè)錯(cuò)誤(使用 trigger_error())呛凶,你需要對(duì)數(shù)據(jù)/文件做清理回收。
重要的是要記住 error_types 里指定的錯(cuò)誤類型都會(huì)繞過(guò) PHP 標(biāo)準(zhǔn)錯(cuò)誤處理程序行贪, 除非回調(diào)函數(shù)返回了 FALSE漾稀。 error_reporting() 設(shè)置將不會(huì)起到作用而你的錯(cuò)誤處理函數(shù)繼續(xù)會(huì)被調(diào)用 —— 不過(guò)你仍然可以獲取 error_reporting 的當(dāng)前值,并做適當(dāng)處理建瘫。 需要特別注意的是帶 @ error-control operator 前綴的語(yǔ)句發(fā)生錯(cuò)誤時(shí)崭捍,這個(gè)值會(huì)是 0。
同時(shí)注意啰脚,在需要時(shí)你有責(zé)任使用 die()殷蛇。 如果錯(cuò)誤處理程序返回了,腳本將會(huì)繼續(xù)執(zhí)行發(fā)生錯(cuò)誤的后一行橄浓。
以下級(jí)別的錯(cuò)誤不能由用戶定義的函數(shù)來(lái)處理: E_ERROR粒梦、 E_PARSE、 E_CORE_ERROR荸实、 E_CORE_WARNING谍倦、 E_COMPILE_ERROR、 E_COMPILE_WARNING泪勒,和在 調(diào)用 set_error_handler() 函數(shù)所在文件中產(chǎn)生的大多數(shù) E_STRICT昼蛀。

set_exception_handler函數(shù)

set_exception_handler注冊(cè)異常處理函數(shù),這樣當(dāng)有未被catch的異常產(chǎn)生時(shí)圆存,系統(tǒng)會(huì)為我們自動(dòng)調(diào)用注冊(cè)的處理函數(shù)來(lái)處理叼旋。相關(guān)詳細(xì)描述請(qǐng)查看官網(wǎng)文檔set_exception_handler函數(shù)文檔

register_shutdown_function函數(shù)

register_shutdown_function注冊(cè)一個(gè)會(huì)在php中止時(shí)執(zhí)行的函數(shù)注冊(cè)一個(gè) callback ,它會(huì)在腳本執(zhí)行完成或者 exit()后被調(diào)用沦辙。關(guān)詳細(xì)描述請(qǐng)查看官網(wǎng)文檔register_shutdown_function函數(shù)文檔

最后直接上干貨

<?php

class myErrorException
{
    private $fileRootName;

    private $fileName;

    public function __construct(string $fileName = '/tmp/php/', bool $bugType = false)
    {
        $this->fileRootName = $fileName . date('Y-m-d') . '.log';
        if (!$bugType) {
            $this->checkDir();
            $this->errorHandle();
        }
    }

    private function checkDir(){
        $this->fileName = $this->fileRootName . date('Y-m-d') . '.log';
        if (!file_exists($this->fileName) && !is_dir($this->fileRootName)) {
            @mkdir($this->fileRootName, '0777', true);
        }
    }

    /**
     * 注冊(cè)全局的錯(cuò)誤處理函數(shù)
     */
    private function errorHandle()
    {
        // 注冊(cè)自己的錯(cuò)誤處理方法來(lái)代替php的標(biāo)準(zhǔn)錯(cuò)誤處理方式(輸出到頁(yè)面或者記錄到日志)夫植,但是一些嚴(yán)重錯(cuò)誤是無(wú)法通過(guò)這種方式來(lái)處理的
        set_error_handler([$this, '_handleError']);

        // 注冊(cè)異常處理函數(shù),這樣當(dāng)有未被catch的異常產(chǎn)生時(shí)油讯,系統(tǒng)會(huì)為我們自動(dòng)調(diào)用注冊(cè)的處理函數(shù)來(lái)處理详民。
        set_exception_handler([$this, '_handleException']);

        // 注冊(cè)捕捉致命錯(cuò)誤
        register_shutdown_function([$this, '_handleShutdown']);
    }

    /**
     * 錯(cuò)誤處理
     * @param int $level
     * @param string $message
     * @param string $file
     * @param int $line
     * @param array $context
     */
    public function _handleError(int $level, string $message, string $file = '', int $line = 0, array $context = [])
    {
        if (error_reporting() & $level) {
            $this->_logHandle($message, $level, $file, $line);
        }
    }

    /**
     * 未捕捉的異常
     * @param \Throwable $e
     */
    public function _handleException(\Throwable $e)
    {
        if (!$e instanceof \Error) {
            $this->_logHandle($e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());
        } else {
            $this->_logHandle($e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());
        }
    }

    /**
     * 致命錯(cuò)誤
     */
    public function _handleShutdown()
    {
        $error = error_get_last();
        if (!is_null($error)) {
            $this->_logHandle($error['message'], $error['type'], $error['file'], $error['line']);
        }
    }

    /**
     * 日志記錄格式
     * @param $message
     * @param $level
     * @param $file
     * @param $line
     */
    private function _logHandle($message, $level, $file, $line)
    {
        $logData = [
            'message' => $message,
            'level' => $level,
            'file' => $file,
            'line' => $line
        ];
        $logStr = date('Y-m-d H:i:s') . " error => " . json_encode($logData);
        file_put_contents($this->fileRootName, json_encode($logStr));
        throw new \Error($message, 500);
    }
}

$logObj = new myErrorException();
new testBugA();

die('test');

此時(shí)上面的PHP代碼網(wǎng)頁(yè)中顯示:

webLog.png

然后服務(wù)器日志中顯示:

linuxLog.png

du -h / --max-depth=2 | sort -nr | head -5

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陌兑,隨后出現(xiàn)的幾起案子沈跨,更是在濱河造成了極大的恐慌,老刑警劉巖兔综,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件饿凛,死亡現(xiàn)場(chǎng)離奇詭異狞玛,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)涧窒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門心肪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人纠吴,你說(shuō)我怎么就攤上這事硬鞍。” “怎么了戴已?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵固该,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我恭陡,道長(zhǎng)蹬音,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任休玩,我火速辦了婚禮著淆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拴疤。我一直安慰自己永部,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布呐矾。 她就那樣靜靜地躺著苔埋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜒犯。 梳的紋絲不亂的頭發(fā)上组橄,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音罚随,去河邊找鬼玉工。 笑死,一個(gè)胖子當(dāng)著我的面吹牛淘菩,可吹牛的內(nèi)容都是我干的遵班。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼潮改,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼狭郑!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起汇在,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤翰萨,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后趾疚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體缨历,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡以蕴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年糙麦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辛孵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赡磅,死狀恐怖魄缚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情焚廊,我是刑警寧澤冶匹,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站咆瘟,受9級(jí)特大地震影響嚼隘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜袒餐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一飞蛹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灸眼,春花似錦卧檐、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至匕积,卻和暖如春盈罐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闪唆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工盅粪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苞氮。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓湾揽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親笼吟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子库物,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 異常與錯(cuò)誤的區(qū)別 關(guān)于異常處理這一塊,在官方的手冊(cè)上介紹的不夠詳細(xì)贷帮,所以我在這里再做一個(gè)相對(duì)詳細(xì)一點(diǎn)的總結(jié)...
    四月不見(jiàn)閱讀 2,224評(píng)論 0 10
  • 本文介紹php開(kāi)源庫(kù)BooBoo戚揭,是一個(gè)處理php異常和錯(cuò)誤的開(kāi)源庫(kù),通過(guò)簡(jiǎn)單的分析代碼撵枢,我們知道了實(shí)際項(xiàng)目中怎么...
    小聰明李良才閱讀 749評(píng)論 0 6
  • 異常(Exception)用于在指定的錯(cuò)誤發(fā)生時(shí)改變腳本的正常流程民晒。 什么是異常精居? PHP 5 提供了一種新的面向...
    josephok閱讀 572評(píng)論 0 7
  • 先上代碼: 總結(jié): 1.在php中我們平常用的try,catch只能捕獲我們主動(dòng)拋出的異常,當(dāng)然除非你的框架已經(jīng)幫...
    Best博客閱讀 169評(píng)論 0 0
  • 異常(Exception)用于在指定的錯(cuò)誤發(fā)生時(shí)改變腳本的正常流程潜必。 什么是異常靴姿?PHP 5 提供了一種新的面向?qū)?..
    林路同閱讀 661評(píng)論 0 0