是属于php程序自身的问题,一般是由非法的语法,环境问题导致的,使得编译器无法通过检查,甚至无法运行的情况。平时遇到的 warming、notice都是错误,只是级别不同而已。
在PHP中,错误用于指出语法、环境或编程问题。根据错误出现在编程过程中的不同环节,大致可以分为以下4类。
语法错误:是指编写的代码不符合PHP的语法规范。 特点:语法错误最常见,也最容易修复 例如:遗漏了一个分号,就会显示错误信息。这类错误会阻止PHP脚本执行,通常发生在程序开发时,可以通过错误报告进行修复,再重新运行检查。运行错误:一般不会阻止PHP脚本的执行,但会导致程序出现潜在的问题。 例如:在一个脚本中定义了两次同名常量,PHP通常会在第二次定义时提示一条错误信息。虽然PHP脚本继续执行,但第二次定义常量的操作没有执行成功。逻辑错误:最让人头疼,不但不会阻止PHP脚本的执行,也不会显示出错误信息 例如:在if语句中判断两个变量的值是否相等,如果错把比较运算符“==”写成赋值运算符“=”就是一种逻辑错误,很难被发现。环境错误:是由于PHP开发环境配置的问题引起的代码报错 例如:用mb_strlen()这个函数时,如果PHP环境中没有启用mbstring扩展,就会导致程序出错。在 php 中的错误也是有级别的
Parse error >Fatal Error > Waning > Notice > Deprecated
常见的错误类型:
1、Deprecated 最低级别的错误
使用一些过期函数的时候会出现,程序继续执行2、Notice 通知级别的错误
使用一些未定义变量、常量或者数组key没有加引号、访问不存在的数组元素等的时候会出现,程序继续执行 E_NOTICE // 运行时通知。表示脚本遇到可能会表现为错误的情况. E_USER_NOTICE // 用户产生的通知信息。3、Warning 警告级别的错误
Warning错误级别相比Notice更严重一些,说明程序出问题了,需要修改代码,但是不会影响脚本继续执行。 **除零错误**(除法运算前,可以使用if判断除数是否为0,若为0则拒绝执行除法运算); **使用include包含不存在的文件**(使用include前,先用is_file()函数判断该文件是否存在,防止错误发生); E_WARNING // 运行时警告 (非致命错误)。 E_CORE_WARNING // PHP初始化启动过程中发生的警告 (非致命错误) 。 E_COMPILE_WARNING // 编译警告 E_USER_WARNING // 用户产生的警告信息3、Fatal error 错误级别的错误
Fatal error是一种致命错误,在运行时发生。一旦发生该错误,PHP脚本会立即停止执行。 **调用一个不存在的方法**; E_ERROR // 致命的运行错误,错误无法恢复,暂停执行脚本 E_CORE_ERROR // PHP启动时初始化过程中的致命错误 E_COMPILE_ERROR // 编译时致命性错,就像由Zend脚本引擎生成了一个E_ERROR E_USER_ERROR // 自定义错误消息。像用PHP函数trigger_error(错误类型设置为:E_USER_ERROR)4、Parse error(E_PARSE)
Parse error是语法解析错误,当脚本存在语法错误时,无法解析成功,就会发生此错误; 发生此错误时中断程序执行,需要修改代码 **漏写了分号**;在 PHP 中,默认的错误处理很简单。一条错误消息会被发送到浏览器,这条消息带有文件名、行号以及描述错误的消息。 但是这样的报错方式在生产环境是不允许出现的,会影响用户体验,所以在生产环境我们通常会这样设置:
// error_reporting用于设置报告的错误级别 // display_errors用于设置是否显示错误信息 1. 直接配置php.ini文件来显示错误报告 display_errors = off error_reporting = E_ALL & ~E_NOTICE; // (表示报告除E_NOTICE之外的所有级别的错误); 2. 通过 error_reporting() 和 ini_set() 函数 ini_set('display_errors', 0); // 即display_errors = off; error_reporting(E_ALL & ~E_NOTICE) // 设置应该报告何种 PHP 错误;这样虽然把页面上的错误隐藏掉,让用户看不到这些问题;但是导致的问题就是,当我们要复现缺陷的时候,也看不到错误信息,就无从下手,只能猜测。
所以我们需要设置一下错误处理的方式,让错误既报出来,又不报到页面上,影响用户;这时就需要创建自定义错误处理函数。即错误日志功能。
我们创建了一个专用函数,可以在 PHP 中发生错误时调用该函数。
function systemError($errorLevel, $errorMessage) { echo "<b>Error:</b> [$errorLevel] $errorMessage"; // 一般都写到日志中 }当它被触发时,它会取得错误级别和错误消息,然后输出错误级别和消息(在生产环境中,肯定只能输出到日志文件中)。
PHP 的默认错误处理程序是内部的错误处理程序,要想针对所有错误来使用我们自定义的错误处理程序,只能把系统内部的处理程序替换掉,可以用下面的函数:
set_error_handler("systemError"); # 如果你只需要处理特定错误级别的错误,可以给 set_error_handler() 添加第二个参数来规定错误级别。通过尝试输出不存在的变量,来测试这个错误处理程序:
<?php function systemError($errorLevel, $errorMessage) { echo "<b>Error:</b> [$errorLevel] $errorMessage"; } // 设置错误处理函数 set_error_handler("systemError"); // 触发错误 echo($test);以上代码的输出如下所示:
Error: [8] Undefined variable: test设置的自定义函数可以接受最多五个参数:
参数描述error_level必需。为用户定义的错误规定错误报告级别。必须是一个数字。参见下面的表格:错误报告级别的值。error_message必需。为用户定义的错误规定错误消息。error_file可选。规定错误发生的文件名。error_line可选。规定错误发生的行号。error_context可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值(超全局数据$_GET、$_POST等)。这些错误报告级别是用户自定义的错误处理程序处理的不同类型的错误:
值常量描述2E_WARNING非致命的 run-time 错误。不暂停脚本执行。8E_NOTICErun-time 通知。在脚本发现可能有错误时发生,但也可能在脚本正常运行时发生。256E_USER_ERROR致命的用户生成的错误。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_ERROR。512E_USER_WARNING非致命的用户生成的警告。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_WARNING。1024E_USER_NOTICE用户生成的通知。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_NOTICE。4096E_RECOVERABLE_ERROR可捕获的致命错误。类似 E_ERROR,但可被用户定义的处理程序捕获。(参见 set_error_handler())8191E_ALL所有错误和警告。(在 PHP 5.4 中,E_STRICT 成为 E_ALL 的一部分)在程序中,当判断用户的输入无效时,我们可以选择由 trigger_error() 函数触发错误来改变程序走向。
<?php $test = 2; if ($test > 1) { trigger_error("变量值必须小于等于 1"); }可以在脚本中任何位置触发错误,通过添加的第二个参数,能够规定所触发的错误类型。
可能的错误类型:
E_USER_ERROR - 致命的用户生成的 run-time 错误。错误无法恢复。脚本执行被中断。E_USER_WARNING - 非致命的用户生成的 run-time 警告。脚本执行不被中断。E_USER_NOTICE - 默认。用户生成的 run-time 通知。在脚本发现可能有错误时发生,但也可能在脚本正常运行时发生。在本例中,如果 “test” 变量大于 “1”,则发生 E_USER_WARNING 错误。如果发生了 E_USER_WARNING,我们将使用我们自定义的错误处理程序并结束脚本:
<?php function systemError($errorLevel, $errorMessage) { echo "<b>Error:</b> [$errorLevel] $errorMessage"; } // 设置错误处理函数 set_error_handler("systemError", E_USER_WARNING); // 触发错误 $test = 2; if ($test > 1) { trigger_error("变量值必须小于等于 1", E_USER_WARNING); } ?>以上代码的输出如下所示:
Error: [512] 变量值必须小于等于 1 脚本结束执行结果 Parse error: syntax error, unexpected ';' in 文件目录 on line 34 Emmmmm 这不扯淡吗? 分明分明没有执行呢?
其实原因使因为,程序执行前,我们 php 会先检查我们程序的语法问题,如果没有问题,我们才能执行我们的程序。
我们上面的代码没用通过我们的语法检查,所以直接报错。
那么问题来了? 我们在框架中的时候,为什么是框架都是框架给我们报错呢?
在框架中,其代码是通过一个入口文件来加载的。而我们php检测语法错误的时候,只检查我们的 index.php 有没有错误, require 文件中的代码是不会受到检测的。在Index.php 文件中通常会定义一些错误异常的处理。当我们代码出错时,那是在 run-time 中检测的错误,我们的框架可以根据我们编写的错误异常自行做出处理。
下面我们举个例子 在 ThinkPHP5中的异常处理
// [ 应用入口文件 ] index.php namespace think; // 加载基础文件 require __DIR__ . '/../thinkphp/base.php'; // 支持事先使用静态方法设置Request对象和Config对象 // 执行应用并响应 Container::get('app')->run()->send();在我们的入口文件中,加载了 base.php 在这个文件中,TP 定义了自己的异常处理
// 载入Loader类 require __DIR__ . '/library/think/Loader.php'; // 注册自动加载 Loader::register(); // 注册错误和异常处理机制 Error::register(); // 实现日志接口 if (interface_exists('Psr\Log\LoggerInterface')) { //doSomething } // 注册类库别名 Loader::addClassAlias([ //doSomething ]); /** * 注册异常处理 * @access public * @return void */ public static function register() { error_reporting(E_ALL); set_error_handler([__CLASS__, 'appError']); set_exception_handler([__CLASS__, 'appException']); register_shutdown_function([__CLASS__, 'appShutdown']); }可以看到 TP是在入口脚本就注册了 异常处理机制,分别把 Error 、Exception、Shutdown的处理都注册进来。后序所有的异常都不会走PHP原本的异常而是走 TP 自定义的异常。
参考链接