[TOC]
# 異常和錯誤處理
如果每一次去逐一檢查錯誤,會讓代碼變得冗長復雜,到處充斥著`if...else` ,并且嚴重降低代碼的可讀性.而且人的因素也是不可信賴的,程序員可能并不會把這問題當一回事,從而導致業務異常.
**在這種情況下,就逐漸形成了異常處理機制,或者強迫消除這些問題,或者把問題交給能解決他的環境.**
**這就把在正常過程中"做什么事的代碼"和"出了問題怎么辦的代碼"進行分離**
# 和java區別
在各種語言里,異常和錯誤的概念是不一樣的.php里,遇到任何自身錯誤都會觸發一個錯誤,而不是拋出異常(對于一些情況,會同時拋出異常和錯誤.php一旦遇到非正常代碼,通常都會觸發錯誤,而不是拋出異常.這時候想要異常處理是不可預料的,是辦不到的)
~~~
try{
5/0;
}catch(Exception $e) {
echo '異常處理';
}
~~~
對于除零這種"異常"情況,php認為是一個錯誤,直接觸發錯誤(waring也是錯誤,只是等級不同),而不會自動拋出異常進入異常流程,故最終沒有走到異常分支,也沒有處理異常.
php只有你主動throw后,才能捕獲異常(也有些異常,php可以自動捕獲)
php無法自動捕獲有意義的異常,它把所有不正常的情況都視作錯誤,你要捕獲這個異常,就得使用if..else結構.保證代碼是正常的.但php這個機制并不完善,php內置有一些pdo異常,反射異常
~~~
try {
if ((5/0) || 1) {
echo '異常發生了',PHP_EOL;
}
}catch(Exception $e) {
//最終無法catch,因為是錯誤
echo '異常catch住了';
}
~~~
**注意**
**其實php和java之間之所以有這樣的差距,根本在于,在java里,異常是唯一的錯誤報告方式.而在php里卻不是這樣.
通俗一點講,就是這2個語言對異常和錯誤的界定存在分歧.
什么是異常,什么是錯誤,2個語言的設計存在不同的觀點**
**php只有手動拋異常和內置異常機制,才能捕獲異常,否則是先觸發錯誤,再異常**

# 異常
## 自己定義異常
~~~
<?php
class emailException extends exception
{
}
class pwdException extends exception
{
function __toString()
{
//改寫拋出異常結果
return
"<div class=\"error\">
Exception{$this->getCode()}:{$this->getMessage()}
in File:{$this->getFile()}on line:{$this->getLine()}</div>";
}
}
function reg($reginfo=null)
{
if(empty($reginfo['email'])) {
throw new emailException('郵件為空',500);
}
if(empty($reginfo['pwd'])) {
throw new pwdException('密碼沒填寫',501);
}
echo '注冊成功';
}
~~~
處理異常
~~~
try {
reg();
}catch(emailException $e) {
echo $e->getMessage(),$e->getCode();
echo PHP_EOL;
}catch(pwdException $e) {
echo $e;
echo PHP_EOL,'特殊處理';
}catch(Exception $e) {
echo $e->getTraceAsString();
echo PHP_EOL,'其他情況,統一處理';
}
~~~
這段代碼用于捕獲各種拋出的異常,進行分類處理,記住大的exception在最后catch住
## 異常應用場景
**對程序悲觀預測**
并不是指程序員的代碼水平不行,而是有些代碼發生場景無法一一預測,并且有些業務是非常重要的
**對業務關注**
那么就可以在catch的捕獲中進行業務補償處理
合理代碼應該是這樣

**異常處理機制可以把每一件事情當做事務考慮,還可以把異常看作一個內建的恢復系統.
如果程序某部分失敗,異常將恢復到某個已知穩定的點上,而這個點就是程序的上下文環境,而try塊里面的代碼就保存catch所要知道的程序上下文環境.
因此,如果很看重異常,就應該分散進行try...catch..處理**
## 語言健壯級別

## 怎么看php中的異常

# 錯誤
php錯誤處理比異常價值大多了
php錯誤就是會使腳本運行不正常的情況
請確保php.ini做了如下設定
~~~
error_reporting = E_ALL | E_STRICT
display_errors = On
~~~
如果你想隱藏錯誤可以這樣
~~~
error_reporting(0);
或者代碼前面加@
~~~
## 錯誤處理機制
php有一套全局錯誤處理機制set_error_handler,你也可以用trigger_error函數主動拋出一個錯誤
set_error_handler用戶自定義錯誤處理會接管php內置的錯誤處理,你可以在一個頁面使用restore_error_handler來取消接管
注意如果用set_error_handler,代碼中的@也會失效,這種錯誤會顯示
php異常機制是有限的,無法自動拋出異常,必須手動進行,并且內置異常是有限的.
php把很多異常看作是錯誤,這樣可以把這些異常像錯誤一樣用set_error_handler接管,進而進行主動拋出異常

**但是fetal error這種錯誤是捕獲不到的,也無法在發生這個錯誤的時候進行恢復流程處理,但是還有一些特殊方法對這種錯誤進行處理的.
這時候需要一個函數-- register_shutdown_function,這個函數會在php程序終止或者die的時候觸發一個函數,給代碼來個回光返照**
php4時候,類不支持析構函數,常用這個函數模擬實現析構函數
---
對于fetal error還能做點收尾工作,但是php流程的終止必然的,對于Parse error級別錯誤,只能傻眼了,除了可以修改ini文件,什么也做不了
~~~
log_errors = On
error_log = usr/log/php.log
~~~
這樣一旦發生錯誤會被記錄log文件,方便以后查詢
和exception類似,錯誤處理也有對應拋出函數,那就是trigger_error函數,如下

- 書列表
- laravel框架關鍵技術
- 第一章 組件化開發與composer使用
- 簡介
- composer
- 添加路由組件
- 添加控制器模塊
- 添加模型組件
- 添加視圖組件
- 第三章 laravel框架中常用的php語法
- 匿名函數
- 文件包含
- 魔術方法
- 魔術常量
- 反射
- 后期靜態綁定
- traits
- 第四章 laravel框架中使用的HTTP協議基礎
- HTTP協議
- 數據庫
- 數據遷移
- 第六章 laravel框架中的設計模式
- IOC模式
- php核心技術與最佳實踐
- 第一章面向對象核心
- 反射
- 簡單ORM
- 異常和錯誤
- 接口
- 第二章,面向對象設計
- 設計原則
- 單一職責
- 接口隔離
- 開放封閉
- 替換原則
- 依賴倒置
- linux是怎么寫的呢?
- 第三章 正則表達
- 認識正則
- 第四章 php網絡技術應用
- HTTP協議詳解
- php和http相關函數
- 垃圾信息防御措施
- 現代操作系統
- 引論
- sql必知必會
- 限制結果
- 按位置排序
- where求職順序
- IN操作符
- like
- 函數
- group by
- 組合查詢
- 插入檢索出的數據
- 視圖
- 高性能mysql
- 第一章節 mysql架構與歷史
- mysql架構邏輯圖
- 連接與管理
- 優化與運行
- 讀寫鎖
- 鎖粒度
- 表鎖(table lock)
- 行級鎖(row lock)
- ACID
- 隔離級別
- 死鎖
- 隱式和顯式鎖定
- 多版本并發控制
- Innodb概覽
- 第四章節 Schema與數據類型優化
- 選擇優化的數據類型
- 日期和時間類型
- 標識列
- 特殊類型數據
- 表設計中的缺陷
- 范式
- 計數器表
- 第五章 創建高性能索引
- 索引基礎
- 索引類型
- 索引的優點
- 高性能索引策略
- 選擇合適的索引列順序
- 聚簇索引
- 順序的主鍵什么時候會造成更壞的后果
- 覆蓋索引
- 使用索引掃描來做排序
- 壓縮索引
- 冗余和重復索引
- 索引和鎖
- 支持多種過濾條件
- 什么是范圍條件
- 優化排序
- 維護索引和表
- 表損壞
- 減少索引和數據的碎片
- 第六章 查詢性能優化
- 掃描的行數和訪問類型
- 重構查詢方式
- 查詢執行的基礎
- 重構-改善既有代碼設計
- 第一章-重構
- 什么是重構
- 第一個案列
- 重構第一步
- 王垠博客
- 多態取代價格相關邏輯