PHP中的异常处理

时间:2022-08-26 00:23:32

1.什么是异常?异常和错误有什么区别?

1.异常:程序运行与预期不太一致,与错误是两个不同的概念!
2.抛出和捕获异常
3.多个catch块的时候基类要往后放,否则基类捕获异常后就不会往下继续捕获了!
3.先出现错误,在出现异常,所以写api的时候一定要把display_errors关掉
4.php的内置异常

error_reporting(-1);
ini_set('display_errors','off');

//pdo内置异常类
try {
$pdo = new PDO('mysql:host=localhost;dbname=mysql', 'brave', '123456');
var_dump($pdo);
echo '<hr/>';
echo 'continue.......';
} catch (Exception $e) {
echo $e->getMessage();
}
echo 'this is a test.......';

echo '<hr/>';

//spl文件读写内置异常类
try {
$splObj = new SplFileObject('test.txt', 'r');
echo 'read file';
} catch (RuntimeException $e) {
echo $e->getMessage();
}
echo 'continue.......';

echo '<hr/>';

2.异常的基本语法结构

    try {
//需要进行异常处理的代码
throw语句抛出
} catch (PdoException $e) {

try {
throw语句抛出
} catch (Exception $e) {

}

} catch (FileException $e) {

} catch (CustomException $e) {

}

//other code

3.如何自定义异常类?

error_reporting(-1);
ini_set('display_errors','off');
class MyException extends Exception{

function __construct($message, $code=0)
{

parent::__construct($message, $code);
}

public function __toString(){
$message = "<h2>出现异常了,信息如下</h2>";
$message .="<p>".__CLASS__." [{$this->code}]:{$this->message}</p>";
return $message;
}

public function test(){
echo 'this is a test';
}

public function stop(){
exit('script end..............<hr/>');
}

//自定义其他方法
}

try {
echo '出现异常了!';
throw new MyException("测试自定义异常!", 11);
} catch (MyException $e) {
echo $e->getMessage();
echo '<hr/>';
echo $e;
echo '<hr/>';
$e->stop();
$e->test();
}

4.自定义文件异常类

error_reporting(-1);
ini_set('display_errors','off');

class FileException extends Exception
{

public function getDetails()
{

switch ($this->code) {
case 0:
return '没有提供文件!';
break;

case 1:
return '文件不存在!'." trace".$this->getTraceAsString().$this->getLine();
break;

case 2:
return '不是一个文件!'." trace".$this->getTraceAsString().$this->getLine();
break;

case 3:
return '文件不可写!';
break;

case 4:
return '非法文件的操作模式!';
break;

case 5:
return '数据写入失败!';
break;

case 6:
return '文件不能被关闭!';
break;

default:
return '非法!';
break;
}
}
}

class WriteData{
private $_message='';
private $_fp=null;

public function __construct($filename=null, $mode='w'){
$this->_message="文件:{$filename} 模式:{$mode}";
if (empty($filename)) {
throw new FileException($this->_message, 0);
}
if (!file_exists($filename)) {
throw new FileException($this->_message, 1);
}
if (!is_file($filename)) {
throw new FileException($this->_message, 2);
}
if (!is_writable($filename)) {
throw new FileException($this->_message, 3);
}
if (!in_array($mode, array('w', 'w+', 'a', 'a+'))) {
throw new FileException($this->_message, 4);
}
$this->_fp=fopen($filename, $mode);
}

/**
* [write 写数据]
* @param [type] $data [description]
* @return [type] [description]
*/

public function write($data){
if (@!fwrite($this->_fp, $data.PHP_EOL)) {
throw new FileException($this->_message, 5);
}
}

/**
* [close 关闭文件句柄]
* @return [type] [description]
*/

public function close(){
if ($this->_fp) {
if (@!fclose($this->_fp)) {
throw new FileException($this->_message, 6);
$this->_fp=null;
}
}
}

public function __destruct(){
$this->close();
}
}

try {
$fp = new WriteData('test.txt', 'w');
$fp->write('this is a test');
$fp->close();
echo '数据写入成功!';
} catch (FileException $e) {
echo '出问题了:'.$e->getMessage().' 详细信息如下:'.$e->getDetails();
}

5.使用观察者模式处理异常

  1. 定义观察(异常)的类, 可以在代码中动态的添加观察者
    /**
* 观察(异常)的类, 可以在代码中动态的添加观察者
*/

class Observable_Exception extends Exception
{

public static $_observers=array();
public static function attach(Exception_Observer $observer){
self::$_observers[]=$observer;
}

public function __construct($message=null, $code=0){
parent::__construct($message, $code);
$this->notify();
}

public function notify(){
foreach (self::$_observers as $observer) {
$observer->update($this);
}
}

}

2.定义异常观察者基类用于规范每一个观察者

    /**
* 观察者基类,用于规范每一个观察者
*/

interface Exception_Observer{
//强制指定必须是我们规定的观察类
public function update(Observable_Exception $e);

}

3.定义日志观察者

    /**
* 定义日志观察者
*/

class Logging_Exception_Observer implements Exception_Observer{
public $_filename='./log_exception.log';

public function __construct($filename=null){
if ($filename!==null && is_string($filename)) {
$this->_filename=$filename;
}
}

public function update(Observable_Exception $e){
$message="时间:".date('Y-m-d H:i:s').PHP_EOL;
$message.="信息:".$e->getMessage().PHP_EOL;
$message.="追踪信息:".$e->getTraceAsString().PHP_EOL;
$message.="文件:".$e->getFile().PHP_EOL;
$message.='行号:'.$e->getLine().PHP_EOL;
error_log($message, 3, $this->_filename);
}
}

4.定义邮件观察者

    /**
* 定义邮件观察者
*/

class Email_Exception_Observer implements Exception_Observer{
public $_email='732578448@qq.com';

public function __construct($email=null){
if ($email!==null && filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->_email=$email;
}
}

public function update(Observable_Exception $e){
$message="时间:".date('Y-m-d H:i:s').PHP_EOL;
$message.="信息:".$e->getMessage().PHP_EOL;
$message.="追踪信息:".$e->getTraceAsString().PHP_EOL;
$message.="文件:".$e->getFile().PHP_EOL;
$message.='行号:'.$e->getLine().PHP_EOL;
error_log($message, 1, $this->_email);
}
}

5.执行测试

error_reporting(-1);
ini_set('display_errors','off');
//引入观察异常的类
require 'Observable_Exception.php';
//引入观察者基类
require 'Exception_Observer.php';
//引入日志观察者
require 'Logging_Exception_Observer.php';
//引入邮件观察者
require 'Email_Exception_Observer.php';

Observable_Exception::attach(new Logging_Exception_Observer());
//自定义地址记录错误异常
Observable_Exception::attach(new Logging_Exception_Observer('/tmp/test11.log'));
Observable_Exception::attach(new Email_Exception_Observer());
//自定义邮件接收人记录错误异常
Observable_Exception::attach(new Email_Exception_Observer('123456@qq.com'));
class MyException extends Observable_Exception{
public function test(){
echo 'this is a test!';
}

public function test1(){
echo '我是 自定义的方法处理这个异常!';
}
}

try {
throw new MyException("出现异常了,记录一下下!");

} catch (MyException $e) {
echo $e->getMessage();
echo '<hr/>';
$e->test();
echo '<hr/>';
$e->test1();
}

6.自定义异常处理器(set_exception_handler)?

1.目的1处理所有未捕获的异常
2.目的2处理所有我们为放到try catch中的异常

3.自定义异常处理函数

ini_set('display_errors','off');
function exceptionHandler_1($e){
echo '自定义异常处理器1'.__FUNCTION__;
echo '异常信息:'.$e->getMessage();
}

function exceptionHandler_2($e){
echo '自定义异常处理器2'.__FUNCTION__;
echo '异常信息:'.$e->getMessage();
}
set_exception_handler('exceptionHandler_1');
set_exception_handler('exceptionHandler_2');
//恢复到上一次定义过的异常处理函数
restore_exception_handler();
throw new Exception('测试');
echo 'continue........';
echo '<hr/>';

4.自定义异常处理类

/**
* 自定义错误异常类
*/

class ExceptionHandler{
protected $_exception;
protected $_logFile='./testExceptionHandler.log';

function __construct(Exception $e){
//保存异常对象
$this->_exception = $e;
}

public static function handle(Exception $e){
$self = new self($e);
$self->log();
echo $self;
}

public function log(){
$msg=<<<EOF
出现了通知错误,如下
产生通知的文件:{$this->_exception->getFile()}<br>
产生通知的信息:{$this->_exception->getTraceAsString()}
产生通知的行号:{$this->_exception->getLine()}
产生通知的错误号:{$this->_exception->getCode()}
产生通知的时间:{$datetime}
\n
EOF;

echo $msg;
error_log($msg, 3, $this->_logFile);
}

public function __toString(){
$message = <<<EOF
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<h1>出现异常了。。。。。</h1>
<p>刷新下试试</p>
</body>
</html>
EOF;

return $message;
}
}



ini_set('display_errors','off');
set_exception_handler(array('ExceptionHandler', 'handle'));

//放在try catch中的throw
try {
throw new Exception("this is a test!",20010);
} catch (Exception $e) {
echo $e->getMessage();
}

//没放在try catch中的throw
throw new Exception("测试未捕获的自定义的异常处理器hello world!",2008);

7.如何像处理异常一样处理PHP的错误?

1.通过ErrorException

function exception_error_handler($errno, $errstr, $errfile, $errline){
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}

set_error_handler('exception_error_handler');
try {
echo gettype();
} catch (Exception $e) {
echo $e->getMessage();
}

2.自定义异常类

class ErrorToException extends Exception{

public static function handle($errno, $errstr)
{

throw new self($errstr, $errno);
}
}

ini_set('display_errors', 'off');
set_error_handler(array('ErrorToException', 'handle'));
set_error_handler(array('ErrorToException', 'handle'),E_USER_WARNING|E_WARNING);

try {
echo $test;
gettype();
trigger_error('test',E_USER_WARNING);
} catch (Exception $e) {
echo $e->getMessage();
}

8.在发生错误的时候将用户重定向到另一个页面

class ExceptionRedirectHandler{
protected $_exception;
protected $_logFile='./redirectLog.log';
protected $_redirect='404.html';

public function __construct(Exception $e){
$this->_exception=$e;
}

public static function handle(Exception $e){
$self = new self($e);
$self->log();
while (@ob_end_clean());
header('HTTP/1.1 307 Temporary Redirect');
header('Cache-Control:no-cache,must-revalidate');
header('Expires: Wed, 01 Jul 2015 07:40:45 GMT');
header('Location:'.$self->_redirect);
exit(1);
}

public function log($value=''){
error_log($this->_exception->getMessage().PHP_EOL, 3, $this->_logFile);
}
}

ini_set('display_errors','off');
set_exception_handler(array('ExceptionRedirectHandler', 'handle'));
$link = mysql_connect('localhost', 'brave', '123456123');
if (!$link) {
throw new Exception("数据库受到攻击了,赶快去看看吧!");

}

9.设置自定义错误和异常需要传递的参数

异常传递:$msg, $code
错误传递:$errno, $errmsg, $errfile, $errline 可看MyErrorHandler.php