錯誤與異常
在 PHP 7 之前,錯誤處理和異常處理是分開的。
try {
$a = 5 % 0;
} catch (Exception $e) {
echo $e->getMessage();
$a = -1; // 通過異常來處理 $a 為 0 的情況,但是實際上,捕獲不到該異常
}
echo $a; // 無法執行
PHP 7 開始,錯誤也可以像異常那樣丟擲。
try {
$a = 5 % 0;
// 注意,DivisionByZeroError 錯誤只能捕捉到 % 運算,無法捕捉 / 運算
} catch (DivisionByZeroError $e) {
echo $e->getMessage();
$a = -1;
}
echo $a; // -1
相關類
PHP 中的全部異常和錯誤
Throwable - 介面
Error - 所有錯誤的基類
ArithmeticError
DivisionByZeroError
AssertionError
CompileError
ParseError
TypeError
ArgumentCountError
Exception - 所有異常的基類
ClosedGeneratorException
DOMException
ErrorException
IntlException
JsonException
LogicException
BadFunctionCallException
BadMethodCallException
DomainException
InvalidArgumentException
LengthException
OutOfRangeException
PharException
ReflectionException
RuntimeException
OutOfBoundsException
OverflowException
PDOException
RangeException
UnderflowException
UnexpectedValueException
SodiumException
Throwable 介面
Throwable {
abstract public getMessage ( void ) : string
abstract public getCode ( void ) : int
abstract public getFile ( void ) : string
abstract public getLine ( void ) : int
abstract public getTrace ( void ) : array
abstract public getTraceAsString ( void ) : string
abstract public getPrevious ( void ) : Throwable
abstract public __toString ( void ) : string
}
Error 基類
Error implements Throwable {
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] )
final public getMessage ( void ) : string
final public getPrevious ( void ) : Throwable
final public getCode ( void ) : mixed
final public getFile ( void ) : string
final public getLine ( void ) : int
final public getTrace ( void ) : array
final public getTraceAsString ( void ) : string
public __toString ( void ) : string
final private __clone ( void ) : void
}
Exception 基類
Exception {
protected string $message ;
protected int $code ;
protected string $file ;
protected int $line ;
public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] )
final public getMessage ( void ) : string
final public getPrevious ( void ) : Throwable
final public getCode ( void ) : int
final public getFile ( void ) : string
final public getLine ( void ) : int
final public getTrace ( void ) : array
final public getTraceAsString ( void ) : string
public __toString ( void ) : string
final private __clone ( void ) : void
}
除此之外,使用者也可以自定義異常
class ModelNotFoundException extends \RuntimeException
{
protected $model;
public function setModel($model)
{
$this->model = $model;
$this->message = "No query results for model [{$model}]";
return $this;
}
}
// 使用
throw (new ModelNotFoundException)->setModel(get_class($this->model));
自定義異常時,應當以具體錯誤來命名,而不是從釋出者的角度來命名
// 不好的命名
CouldNotCopyFileException
// 好的命名
FileNotFoundException
注意,使用者無法實現 Throwable
介面,只能通過繼承 Error
或 Exception
來實現。
// 報錯:Class MyException cannot implement interface Throwable, extend Exception or Error instead
class MyException implements Throwable {}
// 正確
class MyException extends Exception implements Throwable {}
也可以這麼操作
interface MyThrowable extends Throwable {
public function myCustomMethod();
}
class MyException extends Exception implements MyThrowable {
public function myCustomMethod()
{
// implement custom method code
}
}
使用場景
異常將錯誤處理與常規程式碼進行分離,能夠讓業務流程更加清晰。
try {
// 業務流程
} catch (FileNotFoundException $e) {
} catch (FileTypeException $e) {
} catch (Exception $e) {
}
如果沒有使用異常,那麼在進行業務流程時就必須考慮各種錯誤處理,會讓程式碼的邏輯變得混亂
// 業務流程
// 錯誤處理
// 業務流程
// 錯誤處理
方法檢測到錯誤卻沒有足夠的資訊來進行處理,這時候應該丟擲丟擲異常,讓客戶端來處理異常,有利於保持職責的單一性。
public function foo()
{
if(條件不滿足){
// 丟擲異常,不進行處理,讓客戶端進行處理
}
}
異常機制有利於保持資料一致性很重要,在資料一致性可能被破壞時,就需要使用異常機制進行事後補救。
try {
} cache(Exception $e){
// 執行一些補救措施
}
異常是層層丟擲的,客戶端只需要在合適的時候處理特定的異常即可,不需要一次性處理所有異常。
// 只處理 404 異常
public function actionType($username)
{
try {
$user = $client->get(sprintf("/api/user/%s", $username));
} catch (RequestException $e) {
if (404 === $e->getResponse()->getStatusCode()) {
return "create";
}
throw $e;
}
return "update";
}
為了不洩露敏感資訊,需要一個全域性異常處理程式。
set_exception_handler(function($exception){
echo '發生了未知錯誤';
log($exception->getMessage());
});
點選 連結,免費加入心智極客的知識星球分享群,共同成長。