搜尋
首頁後端開發PHP7PHP7如何使用set_error_handler和set_exception_handler處理異常機制

這篇文章要跟大家介紹PHP7使用set_error_handler和set_exception_handler處理異常機制的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

PHP7如何使用set_error_handler和set_exception_handler處理異常機制

由於歷史原因,php一開始被設計為一門面向過程的語言,所以異常處理沒有使用像Java一樣的try / catch 機制,出錯時直接顯示到頁面上,或記錄到web伺服器的錯誤日誌中,並且php的錯誤分成了很多的級別,例如E_ERROR、E_WARNING、E_PARSE、E_NOTICE等等,對於像E_ERROR、E_PARSE這樣的嚴重錯誤,php會直接終止腳本的運行。

雖然對於php5版本,我們可以使用set_error_handler來註冊自己的錯誤處理方法來代替php的標準錯誤處理方式(輸出到頁面或記錄到日誌),但是一些嚴重錯誤是無法通過這種方式來處理的,具體我們來看手冊對此方法的介紹:

mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

设置一个用户的函数(error_handler)来处理脚本中出现的错误。 

本函数可以用你自己定义的方式来处理运行中的错误, 例如,在应用程序中严重错误发生时,或者在特定条件下触发了一个错误(使用 trigger_error()),你需要对数据/文件做清理回收。 

重要的是要记住 error_types 里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE。 error_reporting() 设置将不会起到作用而你的错误处理函数继续会被调用 —— 不过你仍然可以获取 error_reporting 的当前值,并做适当处理。 需要特别注意的是带 @ error-control operator 前缀的语句发生错误时,这个值会是 0。 

同时注意,在需要时你有责任使用 die()。 如果错误处理程序返回了,脚本将会继续执行发生错误的后一行。 

以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。

手冊上說的很清楚,對於E_ERROR、E_PARSE之類的錯誤並不能被用戶處理,我們來看代碼演示(以下範例用php5.6運行)

<?php
 
//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}
 
set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误
 
 
echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

運行結果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 16

這時錯誤訊息並沒有像往常一樣直接輸出到頁面上,而是按照我們自己的方式來處理了,如果不使用set_error_handler函數,錯誤訊息會是常見的這樣展示,當然我們可以關閉掉php的錯誤顯示,這樣錯誤就不會直接顯示到頁面上了。

Notice: Undefined variable: foo in D:\project\demo\demo.php on line 15

這樣的處理機制看似也還不錯,但上面提到不是所有錯誤都可以這樣處理,修改一下上面的程式碼如下:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误

再來運行:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 15
错误编号errno: 256
错误信息errstr: 人为产生触发一个错误
出错文件errfile: D:\project\demo\demo.php
出错行号errline: 17

Fatal error: Call to undefined function foobar() in D:\project\demo\demo.php on line 19

正如我們所料,前兩個錯誤被我們「捕獲」處理了,而最後的Fatal error並沒有按照我們註冊的錯誤函數來處理,還是使用的預設的處理方式,這也是php5版本的錯誤處理的一大缺陷。 PHP7之後的異常處理方式有了一些新的變化,來看看手冊上的介紹:

PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。 

这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。 

Error 类并非继承自 Exception 类,所以不能用 catch (Exception $e) { ... } 来捕获 Error。你可以用 catch (Error $e) { ... },或者通过注册异常处理函数( set_exception_handler())来捕获 Error。

php7的這種錯誤處理機制有像java學習的意味,這樣使得我們可以自己來處理大多數的異常,下面看程式碼範例(以下程式碼使用php7運行)

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为产生触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
catch (Error $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}

運行結果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为产生触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19
Error code: 0
Error message: Call to undefined function foobar()
Error file: E:\project\demo\demo.php
Error fileline: 21

這樣不同類型的錯誤都可以被我們自己處理了,包括致命錯誤。如果不使用 try / catch , php7的報錯訊息和php5還是有一些不同:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19

Fatal error: Uncaught Error: Call to undefined function foobar() in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21

致命錯誤的描述變成: 拋出的一個Error沒有被捕獲。

注意這裡的catch限定的只能捕獲Error類的錯誤,並且手冊上明確說了Error類並不是Exception類的子類,那我同時想捕獲代碼中的Exception錯誤不是做不到了嗎,請看程式碼:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch

    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
catch (Error $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}

執行結果:

错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 17
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 19

Fatal error: Uncaught Exception: This is a exception in E:\project\demo\demo.php:21 Stack trace: #0 {main} thrown in E:\project\demo\demo.php on line 21

那有沒有什麼辦法呢,其實看手冊上的繼承關係圖


可以看出,Error類別和Exception類別都是Throwable的子類別(其實是Error類別和Exception類別都實作了Throwable介面),所以上面的程式碼可以優化為:

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误


try
{
    echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

    trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

    if (mt_rand(1, 10) > 5)
    {
        throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch
    }
    else
    {
        foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
    }
}
catch (Throwable $e)
{
    echo "Error code: " . $e->getCode() . &#39;<br>&#39;;
    echo "Error message: " . $e->getMessage() . &#39;<br>&#39;;
    echo "Error file: " . $e->getFile() . &#39;<br>&#39;;
    echo "Error fileline: " . $e->getLine() . &#39;<br>&#39;;
}

多次運行可以看到,不管是Exception異常還是Error異常,都可以被捕獲處理了。

如果不想所有的錯誤都用try / catch 處理,還可以使用set_exception_handler註冊異常處理函數,這樣當有未被catch的異常產生時,系統會為我們自動呼叫註冊的處理函數來處理。

<?php

//自定义的错误处理方法
function _error_handler($errno, $errstr ,$errfile, $errline)
{
    echo "错误编号errno: $errno<br>";
    echo "错误信息errstr: $errstr<br>";
    echo "出错文件errfile: $errfile<br>";
    echo "出错行号errline: $errline<br>";
}

set_error_handler(&#39;_error_handler&#39;, E_ALL | E_STRICT);  // 注册错误处理方法来处理所有错误

function _exception_handler(Throwable $e)
{
    if ($e instanceof Error)
    {
        echo "catch Error: " . $e->getCode() . &#39;   &#39; . $e->getMessage() . &#39;<br>&#39;;
    }
    else
    {
        echo "catch Exception: " . $e->getCode() . &#39;   &#39; . $e->getMessage() . &#39;<br>&#39;;
    }
}

set_exception_handler(&#39;_exception_handler&#39;);    // 注册异常处理方法来捕获异常


echo $foo[&#39;bar&#39;];  // 由于数组未定义,会产生一个notice级别的错误

trigger_error(&#39;人为触发一个错误&#39;, E_USER_ERROR); //人为触发错误

if (mt_rand(1, 10) > 5)
{
    throw new Exception(&#39;This is a exception&#39;, 400);  //抛出一个Exception,看是否可以被catch
}
else
{
    foobar(3, 5);   //调用未定义的方法将会产生一个Error级别的错误
}
错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 29
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 31
catch Error: 0 Call to undefined function foobar()


错误编号errno: 8
错误信息errstr: Undefined variable: foo
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 29
错误编号errno: 256
错误信息errstr: 人为触发一个错误
出错文件errfile: E:\project\demo\demo.php
出错行号errline: 31
catch Exception: 400 This is a exception

這時我們可能又會被PHP7弄暈,哪些被set_error_handler處理,哪些被set_exception_handler處理,手冊上也沒有明確說明這塊,根據我的總結,大致上不會導致腳本終止運行的錯誤會被set_error_handler處理,而會終止腳本運行的嚴重錯誤會被當作Error拋出,但不是絕對,上面人為觸發的

E_USER_ERROR就是一個會打斷腳本運行的錯誤,但是併沒有當作Error異常拋出,而是交由set_error_handler註冊的方法處理,這可能是因為這類錯誤是我們自己人為產生的有關,所以PHP7的錯誤處理還是有一些含糊不清,對於我們自己處理時要多加小心。

推薦學習:php影片教學

以上是PHP7如何使用set_error_handler和set_exception_handler處理異常機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:csdn。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具