ThinkPHP 異常處理

zs4336發表於2019-12-18

異常處理

系統產生的異常和錯誤都是程式的隱患,要儘早排除和解決,而不是掩蓋。對於應用自己丟擲的異常則做出相應的捕獲處理
我們在編寫程式碼的時候通常會使用流程語句,當然我們也可以把捕獲異常當成流程與就來使用

Tp在除錯模式下展示異常頁面,顯示具體細節,而在部署模式下,僅顯示錯誤資訊提示,這麼做是為了安全考慮。我們可以手動捕獲異常,如果工程量小的情況下可以,但是如果需要捕獲異常的地方有很多的話,豈不是要寫很多重複的程式碼,雖然利用公共方法可以解決重複問題,但這不是最優解。系統支援異常處理由開發者自定義類進行接管,需要在應用配置檔案app.php中配置引數exception_handle,下面就舉例Api介面的異常處理類。

配置異常處理handle類

在應用配置檔案app.php

'exception_handle'       => 'app\common\exception\handler\ApiExceptionHandler',

定義異常基類

定義app\common\exception\BaseException.php

<?php
namespace app\common\exception;

use think\Exception;

class BaseException extends Exception
{
    //http 狀態碼
    public $code = 500;

    //錯誤碼
    public $errCode = 1000;

    //錯誤訊息
    public $errMsg  = '伺服器內部錯誤';

    public function __construct($error = [])
    {
        if( array_key_exists('code',$error) )
            $this->code = $error['code'];

        if( array_key_exists('errCode',$error) )
            $this->errCode = $error['errCode'];

        if( array_key_exists('errMsg',$error) )
            $this->errMsg = $error['errMsg'];
    }
}

定義異常處理Handle類

我們開發Api的時候,經常會驗證引數安全,以及手動丟擲可視性錯誤,那麼類似這些前端提示性錯誤可以直接返回前端,並且不需要記錄日誌。當然如果在開發除錯模式的話,可以交給系統處理異常,如果不是開發除錯模式,沒必要顯示具體的錯誤,比如返回給前端一大串英文錯誤資訊,客戶看了一臉懵逼,他也不知道具體錯在哪了,互動非常不好,因為客戶端根本不關心這些資訊。像這種情況,統一返回給客戶端提示說伺服器內部錯誤(大部分是我們程式碼的問題),然後記錄日誌,由後端人員再去檢查程式碼,處理好完備的邏輯。

定義app\common\exception\handler\ApiExceptionHandler.php

<?php

namespace app\common\exception\handler;

use app\common\exception\BaseException;
use Exception;
use think\exception\Handle;
use think\facade\Env;
use think\facade\Log;

class ApiExceptionHandler extends Handle
{
    //http 狀態碼
    private $code;

    //錯誤訊息
    private $errMsg;

    //錯誤碼
    private $errCode;

    public function render(Exception $e)
    {
        //表示需要顯示具體錯誤訊息的異常類,並不需要記錄日誌
        if($e instanceof BaseException){
            $this->code    = $e->code;
            $this->errMsg  = $e->errMsg;
            $this->errCode = $e->errCode;
        }else{
            //獲取除錯資訊,如果處於除錯狀態,則顯示具體錯誤資訊,否則統一返回伺服器錯誤訊息,並記錄日誌
            $appDebug = Env::get('app_debug',false);

            //交給系統處理錯誤
            if( $appDebug ){
                return parent::render($e);
            }

            $this->code = 500;
            $this->errCode = 9999;
            $this->errMsg = '伺服器內部錯誤';

            //記錄日誌
            $this->recordLog($e);
        }

        $data = [
            'msg'  => $this->errMsg,
            'code' => $this->errCode,
            'data' => '',
        ];
        return json()->data($data)->code($this->code);
    }

    /**
     * 記錄錯誤日誌
     * @param Exception $e
     */
    public function recordLog(Exception $e)
    {
        $message = $e->getMessage();
        Log::record($message,'error');
    }
}

至此,異常處理已差不多完成,剩下的就是在實際邏輯中丟擲異常,就像上面說的類似流程控制似的,丟擲異常的時候就相當於終止了程式,返回給前端錯誤提示。

趁還沒掉光,趕緊給每根頭髮起個名字吧~