1.php异常是什么?和错误有什么区别?
- PHP 中将代码自身异常(一般是环境或者语法非法所致)称作错误
Error
,将运行中出现的逻辑错误称为异常Exception
- 错误是没法通过代码处理的,而异常则可以通过
try/catch
来处理 -
PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。
这种 Error 异常可以像 Exception 异常一样被第一个匹配的
try
/catch
块所捕获。如果没有匹配的catch
块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。 -
Error 类并非继承自 Exception 类,所以不能用
catch (Exception $e) { ... }
来捕获 Error。你可以用catch (Error $e) { ... }
,或者通过注册异常处理函数( set_exception_handler())来捕获 Error。
try {
echo 10/0;
} catch (\Exception $e) {
echo $e->getMessage(); // Division by zero
}
echo 10/0; // ErrorException: Division by zero in file
$file=fopen("welcome.txt","r"); // ErrorException: fopen(welcome.txt): failed to open stream: No such file or directory in file
注意:php5上面代码是捕获不到的,php7可以。
错误等级
Fatal Error:致命错误(脚本终止运行)
E_ERROR // 致命的运行错误,错误无法恢复,暂停执行脚本
E_CORE_ERROR // PHP启动时初始化过程中的致命错误
E_COMPILE_ERROR // 编译时致命性错,就像由Zend脚本引擎生成了一个E_ERROR
E_USER_ERROR // 自定义错误消息。像用PHP函数trigger_error(错误类型设置为:E_USER_ERROR)
Parse Error:编译时解析错误,语法错误(脚本终止运行)
E_PARSE //编译时的语法解析错误
Warning Error:警告错误(仅给出提示信息,脚本不终止运行)
E_WARNING // 运行时警告 (非致命错误)。
E_CORE_WARNING // PHP初始化启动过程中发生的警告 (非致命错误) 。
E_COMPILE_WARNING // 编译警告
E_USER_WARNING // 用户产生的警告信息
Notice Error:通知错误(仅给出通知信息,脚本不终止运行)
E_NOTICE // 运行时通知。表示脚本遇到可能会表现为错误的情况.
E_USER_NOTICE // 用户产生的通知信息。
2.php拦截异常的函数
(1)set_exception_handler() 设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler
调用后异常会中止。:
set_exception_handler(callable $exception_handler
): callable
(2)set_error_handler() 设置用户自定义的错误处理函数:
set_error_handler(callable $error_handler
, int $error_types
= E_ALL | E_STRICT): mixed
PHP 7.2.0 后此参数被弃用了。 极其不建议依赖它。
(3)register_shutdown_function() — 注册一个会在php中止时执行的函数
register_shutdown_function(callable $callback
, mixed $parameter
= ?, mixed $...
= ?): void
3.Throwable
PHP7 新增了一个全新的接口 Throwable,Exception 和 Error 都实现了 Throwable 接口
Throwable 接口:
interface Throwable
{
public function getMessage(): string;
public function getCode(): int;
public function getFile(): string;
public function getLine(): int;
public function getTrace(): array;
public function getTraceAsString(): string;
public function getPrevious(): Throwable;
public function __toString(): string;
}
class Exception implements Throwable {
...
}
class Error implements Throwable {
...
}
Throwable 可以捕获 try/catch 块中 Exception 和 Error 对象(或是任何未来可能)的异常类型。
如果要捕获特定类型的异常最好使用对应的 ***Exception 处理,Throwable 更偏向于处理未知错误和系统级错误。
在 PHP7 中,要捕获所有的错误应该使用 Throwable 而不是 Exception。
try {
// 逻辑代码
} catch (Throwable $t) {
// 补救处理
}
Error 内部错误
PHP7 中 fatal 或 recoverable 级别的错误都能抛出一个 Error 实例。可以使用 try/catch 块来捕获。$user = [];
try {
$user->getName();
} catch (Error $e) {
// Call to a member function getName() on arrayecho
$e->getMessage();
}
Error 类细分出以下子类:
ArithmeticError:位移操作负数位或调用 intdiv() 时分子是 PHP_INT_MIN 且分母是 -1 (这个使用除法运算符的表达式:PHP_INT_MIN / -1,结果是浮点型)
DivisionByZeroError:intdiv() 的分母是 0 或者取模操作 (%) 中分母是 0
AssertionError:assert() 的条件不满足
CompileError:编译错误
ParseError:include/require 文件或 eval() 代码存在语法错误
TypeError:函数参数或返回值不符合声明的类型
ArgumentCountError:递给用户定义的函数或方法的参数太少时被抛出
Exception 异常
RuntimeException
RuntimeExcption是执行异常,指程序身本以外无法由开发者控制的状况。 例如呼叫数据库,但是数据库没有回应,或者呼叫远程 API ,可是 API 却没有传回正确的数值。 另外也包含档案系统或环境的问题,例如程序要抓取的的某个外部档案不存在,或者应该安装的外部函式库没有正常运作,这些因为都不是开发者可以控制的,我们就统称为 RuntimeException。 Web 开发最常见的状况就是数据库连接失败,或者SQL查询错误。 例如 PDO 所丢出来的 PDOException 就是既承自 RuntimeException。 所以我们要判断是否是数据库错误可以这样写:
try {
// some database operation
$db->fetch();
} catch (RuntimeException $e) {
// Database error
} catch (Exception $e) {
// Other error
}
LogicException
LogicException 则是反过来,属于程序本身的问题,应该要是开发者事前就解决的问题。 例如某个应该要被 Override 的 method 没有被 override,但 class 本身又因故无法设为 abstract 时,我们就在 method 中丢出 LogicException,要求开发者一定要处理这个问题。 另外,class未被引入,呼叫不存在的对象,或是你把数值除以零等等都属于此例外。class Command
{
public function execute()
{
if ($this->handler instanceof Closure) {
return $this->handler();
}
throw new LogicExcpetion('Handler should be callable.');
}