php服务 错误 异常

错误和异常

error:不能在编译期发现的运行的错误,比如试图用 echo 输出一个未赋值的变量,这类问题往往导致程序或逻辑无法继续下去而需要中断;

exception:php里的异常,是程序运行中的不符合预期的情况,即一种在程序执行流程里面允许发生,只是和正常流程不同的状况。它是一种不正常的情况,就是按照我们的正常逻辑本不该出错,但仍然会出现的错误,属于逻辑和业务流程的错误,而不是语法上的错误。

php里的错误则是一种非法的,语法或者环境问题导致的让编译器无法通过检查,甚至无法运行的情况。

php的异常处理所做的是对你程序运行时出现的某种情况进行处理,并不是错误,异常是程序运行得到的结果不是你想要的。对于程序而言,异常是不可控的,我们无法控制运行时在哪个环节会出错,但是我们可以大致预期到哪些环节会出错,并进行针对性的补救。

错误提示

错误处理-trigger_error

trigger_error(error_message,error_types) 用于在用户指定的条件下触发一个错误消息。 错误抛出

它与内建的错误处理器一同使用,也可以与由 set_error_handler() 函数创建的用户自定义函数使用。如果指定了一个不合法的错误类型,该函数返回 false,否则返回 true。错误处理

语法

set_error_handler(error_function,error_types)

参数 描述

error_function 必需。规定发生错误时运行的函数。

error_types 可选。规定在哪个错误报告级别会显示用户定义的错误。默认是 "E_ALL"。

一个参数为自定义函数的名称,第二个为错误级别

错误处理-实例

PHP错误处理

在实际开发中,错误及异常捕捉仅仅靠try{}catch()是远远不够的。

所以引用以下几中函数。

a) set_error_handler

一般用于捕捉 E_NOTICE 、E_USER_ERROR、E_USER_WARNING、E_USER_NOTICE

不能捕捉:

E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR and E_COMPILE_WARNING。

一般与trigger_error("...", E_USER_ERROR),配合使用。

错误处理-实例

//error handler function

function customError($errno, $errstr, $errfile, $errline)

{

echo "<b>Custom error:</b> [$errno] $errstr<br />";

echo " Error on line $errline in $errfile<br />";

echo "Ending Script";

die();

}

//设置如何处理错误函数

//set error handler

set_error_handler('customError', E_USER_WARNING);


//根据条件抛出错误
$test=2;

//trigger error

if ($test>1)

{

trigger_error("A custom error has been triggered",E_USER_WARNING);

}

错误等级和配置

前台是否要显示

display_errors=Off

如果显示 显示的级别

error_reporting = E_ALL & ~E_NOTICE

是否写入日志

log_errors=On

指定产生的错误报告写入的日志文件位置

error_log = php_errors.log

异常处理-定义

异常处理用于在指定的错误(异常)情况发生时改变脚本的正常流程。这种情况称为异常。

当异常被触发时,通常会发生:

当前代码状态被保存

代码执行被切换到预定义的异常处理器函数

根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行脚本

错误和异常

PHP异常处理详解

异常处理(又称为错误处理)功能提供了处理程序运行时出现的错误或异常情况的方法。

  异常处理通常是防止未知错误产生所采取的处理措施。异常处理的好处是你不用再绞尽脑汁去考虑各种错误,这为处理某一类错误提供了一个很有效的方法,使编程效率大大提高。当异常被触发时,通常会发生:

当前代码状态被保存

代码执行被切换到预定义的异常处理器函数

根据情况,处理器也许会从保存的代码状态重新开始执行代码,终止脚本执行,或从代码中另外的位置继续执行脚本

PHP 5 提供了一种新的面向对象的异常错误处理方法。可以使用检测(try)、抛出(throw)和捕获(catch)异常。即使用try检测有没有抛出(throw)异常,若有异常抛出(throw),使用catch捕获异常。

一个 try 至少要有一个与之对应的 catch。定义多个 catch 可以捕获不同的对象。PHP 会按这些 catch 被定义的顺序执行,直到完成最后一个为止。而在这些 catch 内,又可以抛出新的异常。

异常处理-方法

1.异常的基本使用

2.创建自定义的异常处理器

3.多个异常

4.重新抛出异常

5.设置顶层异常处理器

异常-异常的使用

当一个异常被抛出时,其后的代码将不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。如果一个异常没有被捕获,而且又没用使用set_exception_handler() 作相应的处理的话,那么 PHP 将会产生一个严重的错误,并且输出未能捕获异常(Uncaught Exception ... )的提示信息。

抛出异常,但不去捕获它:

[php] view plain copy

print?

<?php

ini_set('display_errors', 'On');

error_reporting(E_ALL & ~ E_WARNING);

$error = 'Always throw this error';

throw new Exception($error);

// 继续执行

echo 'Hello World';

?>

上面的代码会获得类似这样的一个致命错误:

[plain] view plain copy

print?

Fatal error: Uncaught exception 'Exception' with message 'Always throw this error' in E:\sngrep\index.php on line 5

Exception: Always throw this error in E:\sngrep\index.php on line 5

Call Stack:

0.0005 330680 1. {main}() E:\sngrep\index.php:0

异常&捕获-Try, throw 和 catch

Try, throw 和 catch

要避免上面例子出现的错误,我们需要创建适当的代码来处理异常。

Try - 使用异常的函数应该位于 "try" 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。

Throw - 这里规定如何触发异常。每一个 "throw" 必须对应至少一个 "catch"

Catch - "catch" 代码块会捕获异常,并创建一个包含异常信息的对象

异常&捕获-异常的规则

需要进行异常处理的代码应该放入 try 代码块内,以便捕获潜在的异常。

每个 try 或 throw 代码块必须至少拥有一个对应的 catch 代码块。

使用多个 catch 代码块可以捕获不同种类的异常。

可以在 try 代码块内的 catch 代码块中再次抛出(re-thrown)异常。

简而言之:如果抛出了异常,就必须捕获它。

2. Try, throw 和 catch

要避免上面这个致命错误,可以使用try catch捕获掉。

处理处理程序应当包括:

Try - 使用异常的函数应该位于 "try" 代码块内。如果没有触发异常,则代码将照常继续执行。但是如果异常被触发,会抛出一个异常。

Throw - 这里规定如何触发异常。每一个 "throw" 必须对应至少一个 "catch"

Catch - "catch" 代码块会捕获异常,并创建一个包含异常信息的对象

抛出异常并捕获掉,可以继续执行后面的代码:

<?php

try {

$error = 'Always throw this error';

throw new Exception($error);

// 从这里开始,tra 代码块内的代码将不会被执行

echo 'Never executed';

} catch (Exception $e) {

echo 'Caught exception: ', $e->getMessage(),'<br>';

}

// 继续执行

echo 'Hello World';

?>

在 "try" 代码块检测有有没有抛出“throw”异常,这里抛出了异常。

"catch" 代码块接收到该异常,并创建一个包含异常信息的对象 ($e)。

通过从这个 exception 对象调用 $e->getMessage(),输出来自该异常的错误消息

为了遵循“每个 throw 必须对应一个 catch”的原则,可以设置一个顶层的异常处理器来处理漏掉的错误。

异常&捕获-自定义Exception 类

创建一个自定义的 Exception 类

创建自定义的异常处理程序非常简单。我们简单地创建了一个专门的类,当 PHP 中发生异常时,可调用其函数。该类必须是 exception 类的一个扩展。

这个自定义的 exception 类继承了 PHP 的 exception 类的所有属性,您可向其添加自定义的函数。

异常&捕获-扩展 PHP 内置异常处理类

用户可以用自定义的异常处理类来扩展 PHP 内置的异常处理类。以下的代码说明了在内置的异常处理类中,哪些属性和方法在子类中是可访问和可继承的。(注:以下这段代码只为说明内置异常处理类的结构,它并不是一段有实际意义的可用代码。)

<?php

class Exception

{

protected $message = 'Unknown exception'; // 异常信息

protected $code = 0; // 用户自定义异常代码

protected $file; // 发生异常的文件名

protected $line; // 发生异常的代码行号

function __construct($message = null, $code = 0);

final function getMessage(); // 返回异常信息

final function getCode(); // 返回异常代码

final function getFile(); // 返回发生异常的文件名

final function getLine(); // 返回发生异常的代码行号

final function getTrace(); // backtrace() 数组

final function getTraceAsString(); // 已格成化成字符串的 getTrace() 信息

/* 可重载的方法 */

function __toString(); // 可输出的字符串

}

如果使用自定义的类来扩展内置异常处理类,并且要重新定义构造函数的话,建议同时调用 parent::__construct() 来检查所有的变量是否已被赋值。当对象要输出字符串的时候,可以重载__toString() 并自定义输出的样式。

异常&捕获-嵌套异常处理

如果在内层 "try" 代码块中异常没有被捕获,则它将在外层级上查找 catch 代码块去捕获。

try {

try {

throw new MyException('foo!');

} catch (MyException $e) {

/* 重新抛出 rethrow it */

$e->customFunction();

throw $e; }

} catch (Exception $e) {

var_dump($e->getMessage());

}

5. 设置顶层异常处理器 (Top Level Exception Handler)

set_exception_handler() 函数可设置处理所有未捕获异常的用户定义函数。

<?php

function myException($exception) {

echo "<b>Exception:</b> " , $exception->getMessage();

}

set_exception_handler('myException');

throw new Exception('Uncaught Exception occurred');

输出结果:

Exception: Uncaught Exception occurred

异常&捕获-catch

当异常被抛出时,其后的代码不会继续执行,PHP 会尝试查找匹配的 "catch" 代码块。

如果异常没有被捕获,而且又没用使用 set_exception_handler() 作相应的处理的话,那么将发生一个严重的错误(致命错误),并且输出 "Uncaught Exception" (未捕获异常)的错误消息。

设置顶层异常处理器 (Top Level Exception Handler)

set_exception_handler() 函数可设置处理所有未捕获异常的用户定义函数。

set_exception_handler("exception_function");

function exception_function($e){

echo $e->getCode();

}

b) set_exception_handler

设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。

与throw new Exception('Uncaught Exception occurred'),连用。

c) register_shutdown_function

执行机制是:php把要调用的函数调入内存。当页面所有PHP语句都执行完成时,再调用此函数。

一般与trigger_error("...", E_USER_ERROR),配合使用。

异常&捕获-catch

6. 异常的规则

需要进行异常处理的代码应该放入 try 代码块内,以便捕获潜在的异常。

每个 try 或 throw 代码块必须至少拥有一个对应的 catch 代码块。

使用多个 catch 代码块可以捕获不同种类的异常。

可以在 try 代码块内的 catch 代码块中再次抛出(re-thrown)异常。

简而言之:如果抛出了异常,就必须捕获它,否则程序终止执行。

在我们实际开发中,错误及异常捕捉仅仅靠try{}catch()是远远不够的。

set_error_handler

一般用于捕捉 E_NOTICE 、E_USER_ERROR、E_USER_WARNING、E_USER_NOTICE

不能捕捉:

E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR and E_COMPILE_WARNING。

一般与trigger_error("...", E_USER_ERROR),配合使用。

PHP异常错误关系

在php里,它遇到任何的自身错误都会触发一个错误,而不是抛异常(对于一些情况,会同时抛出异常和错误)。

php一旦遇到非正常的代码,通常都会触发错误,而不是抛出异常。在这个意义上,如果你想使用异常来处理不可预料的问题,是办不到的。

比如说,你想在文件不存在,数据库连接打不开的时候触发异常,是不可行的。这在php里是一种错误,php把它作为错误抛出,而无法作为异常自动捕获。而java则不同,java把很多行为看成是异常并且可捕获。

运算1/0 出现错误warning提示

由以上运行结果可以看到,对于除0这种“异常”代码,php认为这是一个错误,会直接触发错误(waring也是错误,只是错误等级不一样而已),而不会自动抛异常使进入异常流程,故最终$a的值并不是预想中的-1,也就是说,并没有进入异常分支,也没有处理异常。

php只有你主动throw后,才能捕获异常(一般情况是这样的,也有一些异常php可以自动捕获)。

三种场景-异常处理机制

(1)对程序的悲观预测

如果一个程序员对自己的代码带有“悲观情绪”,这里并不是指该程序员代码质量不高。他认为自己的代码无法一一处理各种可预见的不可预见的情况,那该程序员就会进行异常处理。

假设一个场景,程序员悲观地认为自己的这段代码在高并发条件下可能产生死锁,那么他就会悲观地抛出异常,然后在死锁时进行捕获,对异常进行细致的处理。

(2)程序的需要和对业务的关注

如果程序员希望业务代码中不会充斥大堆的打印,调试等处理,通常他们会使用异常机制;或者业务上需要定义一些自己的异常,这个时候就需要自定义一个异常, 来对现实世界中各种各样的业务进行补充。

比如上班迟到,这种情况,我就认为是一个异常,要收集起来,到月底集中处理,扣你工资;如果程序员希望有预见性地处理可能发生的会影响正常业务的代码,那么它需要异常。在这里,强调了异常是业务处理中必不可少的环节,不能对异常视而不见。异常机制认为,数据一致很重要,在数据一致性可能被破坏时,就需要异常机制来进行预先补救。

举个例子,比如有个上传文件的业务需求,要把上传的文件保存在一个目录里,并在数据库里插入这个文件的记录,那么这两步就是互相关联密不可分的一个集成的业务,缺一不可。文件保存失败,而插入记录成功就会导致无法下载文件;而文件保存成功数据库写入失败,则会导致没有记录的文件成为死文件,永远得不到下载。

那么我们假设文件保存成功后没有提示,但是保存失败会自动抛出异常,访问数据库也一样,插入成功没有提示,失败则自动抛出异常,我们就可以把这两个有可能抛出异常的代码段包在一个try语句里,然后在catch捕捉错误,在catch代码段里删除没有被记录到数据库的文件或者删除没有文件的记录,以保证业务数据的一致性。

因此,从业务这个角度讲,异常偏重于保护业务数据一致性,并且强调了对异常业务的处理。

如果我们的代码中,只是象征性的try-catch,最后打印一个报错,over。这样的异常,不如不用,没有体现了异常的思想。所以,合理的代码应该如下:

<?php

try{

//可能出错的代码段

if(文件上传不成功) throw(上传异常);

if(插入数据库不成功) throw(数据库操作异常);}catch(异常){

必须的补救措施,如删除文件,删除数据库插入记录,这个处理很细致

}

//....

上面的两种捕获异常的方式,前一种是在异常发生时,立刻捕获;后一种是分散抛异常,集中捕获。那到底应该是哪一种呢?

如果我们的业务很重要,那么异常越早处理越好,以保证程序在意外情况下能保持业务处理的一致性。比如一个操作有多个前提步骤,突然最后一个步骤异常了,那么其他前提操作都要消除掉才行,保证数据一致性。并且在这种核心业务下,有大量的代码来做善后工作,进行数据补救,这是一种比较悲观的异常。

如果我们的异常不是那么重要,并且在单一入口,MVC风格的应用中,为了保持代码流程的统一,则常常采用后一种异常处理方式,这种异常处理更多强调了业务流程的走向,对善后工作并不是很关心。这是一种乐观的异常

(3)语言级别的健壮性要求

在这点上,php是缺失的。以java为例,java是一种面向企业级开发的语言,强调健壮性。java中支持多线程,java认为,多线程被中断这种情况是彻彻底底的无法预料和避免的。所以 java规定,凡是用了多线程,就必须正视这种情况。你要么抛出,不管它,要么捕获,进行处理。

总之,你必须面对 InterruptedException这个异常,不准回避。也就是异常发生后应对重要数据业务进行补救,当然你可以不做,但是我会告诉你,这是你应该做的。 这类异常是强制的。更多的异常是非强制的,由程序员决定的。java对异常的这种分类和约束,保证了java程序的健壮性和可信赖度。

那么异常的意义何在?

异常就是无法控制的运行时错误,会导致出错时中断正常逻辑运行,该异常代码后面的逻辑都不能继续运行。那么try/catch的好处就是可以把异常造成的逻辑中断破坏降到最小范围内,并且经过补救处理措施后不影响业务逻辑的完整性,

乱抛异常和只抛不捕获,或捕获而不补救,会导致数据混乱。 这就是异常处理的一个重要作用,就是在我们精确控制运行时流程的时候,在程序中断的时候,有预见的用try缩小可能出错的影响范围,再及时捕获异常的发生并作出相应的补救,以使逻辑流程仍然能回到正常轨道上来。

怎样看php的异常?

我们已经看到了php中的异常机制是很鸡肋的,绝大多数情况下无法自动抛异常,必须用if-else来先进行判断,再手工抛出异常。这种处理方式看起来,比较像是多此一举。手动抛异常的意义就不是很大了,因为你手动抛异常也就意味着你在代码里已经充分预期到错误的出现了,也就算不得真正的“异常”了,而是意料之中的了。还是陷入了纷繁复杂的业务逻辑判断和处理中。

java和C++语言做的比较好的就是定义了一堆内置的常见的异常,不需要程序员判断各种异常情况后手工抛出,编译器会代我们进行判断业务是否发生错误,自动抛出异常。作为程序员,则只需要关心异常的捕获和随后补救,而不是像php中关注到底会发生哪些异常啊,用if-else来逐一判断,逐一抛异常。

php的异常机制很不完美,很多情况下和if-else相比没有明显的优势,这也是php的异常没有普及的原因。当然了,使用了异常也能一定程度上降低耦合性。

完善php原先的异常处理机制

那怎么来完善php原先的异常处理机制呢?这时,就要借助php的错误处理了。

PHP提供了一个set_error_handler函数,可以自定义错误处理函数,能够把非致命类型的错误处理都转向到自己定义的函数里进行分析和处理。但是因为出错的地方可能很多,集中处理的话要区分的情况很复杂,所以我们只用这个特性做个跳板。

在自定义函数里我们手动抛一个异常出来,杀个回马枪,让try/catch可以捕获并处理这个运行时错误所带来的中断,从而实现扩大try/catch影响范围的目的.

相关链接

http://www.111cn.net/phper/php/43526.htm

http://blog.csdn.net/hguisu/article/details/7464977

发布了53 篇原创文章 · 获赞 61 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_40884473/article/details/88912000