申明: 本文彩用 CC BY-NC-ND 4.0 受权。
原先的 PHP 只有谬误不异样。看一些老的文档你能看到很多谬误输入是间接 echo html 标签的。而古代一点的框架早曾经包裹好了所有,间接抛出异样就能够有比拟美丽的谬误显示页面,比方 rails 的 better errors。当然,PHP 的古代框架也曾经做的没有错了,比方 laravel。但是我司今朝仍是用 codeigniter 2,它的谬误以及异样解决还比拟粗陋。借着晋级到 PHP7 的契机梳理了一下 PHP 的谬误以及异样解决的机制。
保举教程:《PHP教程》
PHP 的谬误以及异样
PHP5 曾经完成了异样的解决,这以及其余言语差异没有年夜,无非就是 try, catch, uncaught,按下没有表,先说谬误。
PHP 的谬误
除了了异样 PHP5 常见的就是抛犯错误。你能够正在民间文档找到一切的谬误的界说,这些谬误能够大抵分为 WARNING, ERROR(fatal error), NOTICE 等1。PHP的谬误机制总结一文中给出了每一种谬误呈现的场景。
E_DEPRECATED(8192) 运转时告诉,启用后将会对正在将来版本中可能无奈失常工作的代码给出正告。
E_USER_DEPRECATED(16384) 是由用户本人正在代码中应用PHP函数 trigger_error() 来孕育发生的
E_NOTICE(8) 运转时告诉。示意剧本遇到可能会体现为谬误的状况
E_USER_NOTICE(1024) 是用户本人正在代码中应用PHP的trigger_error() 函数来孕育发生的告诉信息
E_WARNING(2) 运转时正告 (非致命谬误)
E_USER_WARNING(512) 用户本人正在代码中应用PHP的 trigger_error() 函数来孕育发生的
E_CORE_WARNING(32) PHP初始化启动进程中由PHP引擎外围孕育发生的正告
E_COMPILE_WARNING(128) Zend剧本引擎孕育发生编译时正告
E_ERROR(1) 致命的运转时谬误
E_USER_ERROR(256) 用户本人正在代码中应用PHP的 trigger_error()函数来孕育发生的
E_CORE_ERROR(16) 正在PHP初始化启动进程中由PHP引擎外围孕育发生的致命谬误
E_COMPILE_ERROR(64) Zend剧本引擎孕育发生的致命编译时谬误
E_PARSE(4) 编译时语法解析谬误。解析谬误仅仅由剖析器孕育发生
E_STRICT(2048) 启用 PHP 对代码的修正倡议,以确保代码具备最好的互操作性以及向前兼容性
E_RECOVERABLE_ERROR(4096) 可被捕获的致命谬误。 它示意发作了一个可能十分风险的谬误,然而尚未招致PHP引擎处于没有稳固的状态。 假如该谬误不被用户自界说句柄捕捉 (参见 set_error_handler() ),将成为一个 E_ERROR 从而剧本会终止运转。
E_ALL(30719) 一切谬误以及正告信息(手册上说没有蕴含E_STRICT, 通过测试实际上是蕴含E_STRICT的)。
常见的有:
<?php // E_ERROR nonexist(); // PHP Fatal error: Call to undefined function nonexist() throw new Exception(''); // 未捕捉异样也是 fatal error // E_NOTICE $a = $b; // PHP Notice: Undefined variable $a = []; $a[2]; // PHP Notice: Undefined offset: 2 // E_WARNNING require 'nonexist.php' // warning and fatal error
因为汗青缘由,这个老旧的 ci2 框架有很多没有正当之处,比方会读取没有存正在的 log 文件;咱们对 PHP 也有一些没有标准的应用,比方:
<?php $req = []; $user_id = $req['user_id']; // PHP error: Undefined offset if (null === $user_id) { /* do something */}
咱们的代码很多中央较为依赖这类猎取没有存正在 key 失去 null 的体现,而每一次这样应用都是会有一个 E_NOTICE 谬误的。尽管能够经过 array_exists 来做 if else,但究竟结果比拟费事。PHP7 之后能够经过数据构造插件来应用 Map, Set, Vector 等明白的数据构造,从而较好的处理这个成绩。
PHP 对谬误的解决
假如不做任何设置装备摆设,PHP 的谬误是会间接打印进去的。陈旧的 PHP 使用也的确有这么做的。但古代使用显然不克不及这样,古代使用的谬误应该遵照一下规定2:
肯定要让 PHP 陈诉谬误;
正在开发环境中要显示谬误;
正在消费环境中不克不及显示谬误;
正在开发以及消费环境中都要记载谬误。
正在消费环境下,谬误不克不及间接打印进去,应该记到 log 文件中,并前往用户一个笼统的谬误信息。set_error_handler 函数就是设置用户自界说的谬误解决函数,以解决剧本中呈现的谬误。咱们能够正在这个函数中将谬误信息打到 log 文件中,并对立前往谬误信息。
原本这个函数是搭配 trigger_error 函数应用的。用户经过 trigger_error 孕育发生 error,而后用 error_handler 来解决谬误。只是正在这类场景下往往「异样」更好用,以是这么用的其实不多。
正在前述的零碎自带的 16 种谬误中,有一局部相称首要的谬误其实不能被 error_handler 捕捉3:
如下级此外谬误不克不及由用户界说的函数来解决: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、E_COMPILE_WARNING,以及正在挪用 set_error_handler() 函数所正在文件中孕育发生的年夜少数 E_STRICT。
这些谬误将无奈记载上去,同时也没有不便对立解决4。正在 PHP7 以前的 PHP 版本一个很年夜的痛点就是:发作了 E_ERROR 谬误,无奈捕捉,招致数据库的事务无奈回滚造成数据纷歧致5。
另一个需求留意的是, error_handler 解决终了,剧本将会持续执行发作谬误的后一行。正在某些状况下,你可能心愿遇到某些谬误能够中缀剧本的执行。正在民间文档中已阐明,
同时留意,正在需求时你有责任应用 die()。 假如谬误解决顺序前往了,剧本将会持续执行发作谬误的后一行。
也就是说,某些状况下,咱们解决完 E_WARNING 之后,需求实时加入剧本(即 die() 或许 exit())。
PHP 异样
异样是对顺序谬误的一种优秀的解决形式,较于谬误,异样的优点是默许打印挪用栈,便于调试,可控等,能够参考一下鸟哥的文章咱们何时应该应用异样,明晰的点清楚明了谬误码以及异样的优缺陷。
对异样的解决也要遵照前述的谬误解决规定2。正在咱们的一样平常开发中,不成能保障能够 catch 一切的异样,而未被 catch 的异样将以 fatal error 的方式中缀剧本的执行并输入谬误信息。以是要借助 set_exception_handler,对立解决一切未被 catch 的异样。咱们能够像 error_handler 那样,正在 exception_handler 中解决 log,将数据库的事务回滚。
后面提到,error_handler 需求正在须要的时分手动中缀剧本, PHP 文档中给出的一种理论是,正在 error_handler 中 throw ErrorException,代码示例以下:
<?php function exception_error_handler($severity, $message, $file, $line) { if (!(error_reporting() & $severity)) { // This error code is not included in error_reporting return; } throw new ErrorException($message, 0, $severity, $file, $line); } set_error_handler("exception_error_handler"); /* Trigger exception */ strpos();
这样但凡没有想疏忽的 error,城市以 Uncaught ErrorException 的方式前往并中缀剧本。
PHP 异样机制
鸟哥经过一个例子解说了 PHP 的异样的解决机制,正在这里转述一下。
<?php function onError($errCode, $errMesg, $errFile, $errLine) { echo "Error Occurred\n"; throw new Exception($errMesg); } function onException($e) { echo '********exception: ' . $e->getMessage(); } set_error_handler("onError"); set_exception_handler("onException"); require("nonexist.php");
其运转后果为
- Error Occurred
- PHP Fatal error
而 onException 并无执行到,阐明正在 error_handler 中 throw exception 没有会被 exception_handler 截获。
require 没有存正在的文件会抛出两个谬误,
- WARNING : 正在PHP试图关上这个文件的时分抛出
- E_COMPILE_ERROR : 从PHP关上文件的函数前往失败当前抛出
PHP 中的异样解决机制以下:
而PHP正在遇到 Fatal Error 的时分,会间接 zend_bailout,而 zend_bailout 会招致顺序流程间接跳过下面代码段,也能够了解为间接 exit 了(longjmp),这就招致了 user_exception_handler 不机会发作作用。
PHP 谬误分类
综上所述,正在 PHP 中,谬误以及异样能够分为如下 3 个种别:异样,可截获谬误,不成截获谬误。异样以及可截获谬误尽管机理没有同,但能够当作是同一种解决形式,而不成截获谬误是另外一种,是一种较为辣手的谬误类型。即刻将会讲到,PHP7 中的 fatal error 是一种承继自 Throwable 的 Error,是能够被 try catch 住的。经过这一形式 PHP7 处理了这一难题。
PHP7 的谬误以及异样
PHP 7 扭转了年夜少数谬误的陈诉形式。没有同于传统(PHP 5)的谬误陈诉机制,如今年夜少数谬误被作为 Error 异样抛出(正在 PHP7 中,只有 fatal error 以及 recoverable error 抛出异样,其余 error 比方 warning 以及 notice 的体现没有变6)。PHP7 中的 Error 以及 Exception 的关系如图 6:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- ArithmeticError extends Error |- pisionByZeroError extends ArithmeticError |- AssertionError extends Error
值患上留意的是,Error 类体现上以及 Exception 根本分歧,能够像 Exception 异样同样被第一个婚配的 try / catch 块所捕捉,假如不婚配的 catch 块,则挪用异样解决函数(事前经过 set_exception_handler() 注册7)进行解决。 假如还没有注册异样解决函数,则依照传统形式解决,被陈诉为一个致命谬误(Fatal Error)。但并不是承继自 Exception 类(要思考到以及 PHP5 的兼容性),以是不克不及用 catch (Exception $e) { ... } 来捕捉,而需求应用 catch (Error $e) { ... },当然,也能够应用 set_exception_handler 来捕捉。
然而,用户不克不及本人界说类完成 Throwable,这是为了保障只有 Exception 以及 Error 才能够抛出。
PHP7 的 ERROR 解决
PHP7 中的 fatal error 会抛出 Error,且能够被失常 catch 到:
<?php $a = 1; try { $a->nonexist(); } catch (Error $e) { // Handle error }
也有些谬误场景下会抛出愈加具体的谬误,比方:
<?php // TypeError function test(int $i) { echo $i; } try { test('test'); } catch (TypeError $e) { // Handle error } // ParseError try{ eval('i=1;'); } catch (ParseError $e) { echo $e->getMessage(), "\n"; } // ArithmeticError try { $value = 1 << -1; } catch (ArithmeticError $e) { echo $e->getMessage(), "\n"; } // pisionByZeroError try { $value = 1 % 0; } catch (pisionByZeroError $e) { echo $e->getMessage(), "\n"; }
Error 以及 Exception 的抉择
当需求自界说解决谬误的时分,应该抉择承继 Error 仍是 Exception 呢?
咱们留意到,PHP7 中是将已经的 fatal error 变为了 Error 抛出,而 fatal error 普通都是一些没有需求正在运转时解决的谬误,这类谬误旨正在提示顺序员,这里的代码写的有成绩,需求修复,而没有是逻辑上要 catch 它做某些营业。
因而,绝年夜少数状况下,咱们其实不需求承继 Error,乃至 catch Error 也没有常见,只正在某些需求 log,回滚数据库,清算现场等场所才需求这样做。
对谬误以及异样的一种理论
依据以上所述,咱们提炼了一个对谬误以及异样解决较好的理论。
- 关于营业中不该该呈现谬误之处,抛出 InternalException,而没有是 Error
<?php class InternalException extends Exception { /*...*/ } function find(Array $ids) { if (empty($ids)) { throw new InternalException('ids should not be empty'); } ... }
- 只正在需求清算现场的时分 catch Error
<?php try { /*...*/ } catch (Throwable $t) { // log, transaction rollback, cleanup... }
- 未捕捉的 Error 以及 Exception 经过 set_exception_handler 做后续清算以及 log
- 其余谬误依然经过 set_error_handler 来解决,正在解决的时分应用愈加明白的 FriendlyErrorType,并抛出 ErrorException 记载挪用栈
FriendlyErrorType:
<?php function FriendlyErrorType($type) { switch($type) { case E_ERROR: // 1 // return 'E_ERROR'; case E_WARNING: // 2 // return 'E_WARNING'; case E_PARSE: // 4 // return 'E_PARSE'; case E_NOTICE: // 8 // return 'E_NOTICE'; case E_CORE_ERROR: // 16 // return 'E_CORE_ERROR'; case E_CORE_WARNING: // 32 // return 'E_CORE_WARNING'; case E_COMPILE_ERROR: // 64 // return 'E_COMPILE_ERROR'; case E_COMPILE_WARNING: // 128 // return 'E_COMPILE_WARNING'; case E_USER_ERROR: // 256 // return 'E_USER_ERROR'; case E_USER_WARNING: // 512 // return 'E_USER_WARNING'; case E_USER_NOTICE: // 1024 // return 'E_USER_NOTICE'; case E_STRICT: // 2048 // return 'E_STRICT'; case E_RECOVERABLE_ERROR: // 4096 // return 'E_RECOVERABLE_ERROR'; case E_DEPRECATED: // 8192 // return 'E_DEPRECATED'; case E_USER_DEPRECATED: // 16384 // return 'E_USER_DEPRECATED'; } return ""; }
error_handler:
<?php function exception_error_handler($severity, $message, $file, $line) { if (!(error_reporting() & $severity)) { // This error code is not included in error_reporting return; } log FriendlyErrorType($severity); throw new ErrorException($message, 0, $severity, $file, $line); } set_error_handler("exception_error_handler");
PHP中的谬误级别与详细报错信息分类 ↩
PHP 最好理论之异样以及谬误 ↩ ↩2
E_ERROR 无奈捕捉,E_RECOVERABLE_ERROR 能够,后者默许输入 Catachable fatal error ↩
fatal error 会记载到 web 效劳器的 error.log,这一点需求留意,由于这个 log 的地位往往没有是 PHP 使用界说的,而是 web 效劳器界说的。 ↩
PHP 中另有一个 register_shutdown_function 函数,它容许注册一个会正在 PHP 停止时执行的函数,这个函数能够捕捉 fatal error,究竟结果是只需是剧本中缀就能够捕捉的。ci2 并无应用这个办法,以是相干成绩不断不失去很好的处理,过后也不认识到这个函数的存正在,晋级 PHP7 之后能够经过 catch Error 来处理,便再也不需求这样解决了。 ↩
Throwable Exceptions and Errors in PHP 7 ↩ ↩2
正在 PHP7 中,传入 exception_handler 的参数从 Exception 改成 Throwable,这象征着 exception_handler 能够截获 Error。 ↩
以上就是探讨php的谬误以及异样解决机制的具体内容,更多请存眷资源魔其它相干文章!
标签: php php7开发教程 php7开发资料 php7开发自学
抱歉,评论功能暂时关闭!