Skip to main content

php7 异常、错误以及相关坑

· 3 min read

php 的坑非常之多,有高低版本的,有历史包袱类的。也有与其他语言不一致导致的知识迁移导致的坑。

前置知识

throwable

PHP 7 changes how most errors are reported by PHP. Instead of reporting errors through the traditional error reporting mechanism used by PHP 5, most errors are now reported by throwing Error exceptions.

(人肉机翻)php 7 改变了php大多数的errors的警告提示方式。和php 5 传统的error reporting 机制不同,php 的大多数错误通过抛出错误异常来警告提示。

填坑开始

例子1 

  • php 版本7,除以0的错误会变成异常
<?php
// test.php
try {
echo 1%0;
} catch (DivisionByZeroError $e) {
echo "bbb";
}
?>

然后执行

php test.php 
bbb

输出bbb ,也就是被try catch 住了。

那么我们先看php 是怎么catch 住这个错误的

堆栈如下:

Breakpoint 1, zend_throw_exception_ex (exception_ce=0x14cfe70, code=0, format=0x1087ea4 "Modulo by zero") at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_exceptions.c:913
913 {
(gdb) bt
#0 zend_throw_exception_ex (exception_ce=0x14cfe70, code=0, format=0x1087ea4 "Modulo by zero") at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_exceptions.c:913
#1 0x00000000009b9feb in ZEND_MOD_SPEC_CONST_CONST_HANDLER () at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:4270
#2 0x0000000000a381e4 in execute_ex (ex=0x7fffef61e030) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:59989
#3 0x0000000000a3d0ab in zend_execute (op_array=0x7fffef684300, return_value=0x0) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:63760
#4 0x000000000094cd22 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend.c:1496
#5 0x00000000008b0b4a in php_execute_script (primary_file=0x7fffffffca10) at /home/dinosaur/Downloads/php-7.2.2/main/main.c:2590
#6 0x0000000000a3fd23 in do_cli (argc=2, argv=0x1441f40) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1011
#7 0x0000000000a40ee0 in main (argc=2, argv=0x1441f40) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1404

相关阅读

例子二

php 版本7

<?php
try {
echo 1/0; // 取余改成了除法
} catch (DivisionByZeroError $e) {
echo "bbb";
}
?>

输出

Warning: Division by zero in /home/dinosaur/test/test.php on line 3
INF

发现了不一样了吗?

① 抛了warning 没有被try catch 住

② php 脚本继续执行,(并输出INF)

我们看看堆栈:

(gdb) bt
#0 zend_error (type=2, format=0x107dcfc "Division by zero") at /home/dinosaur/Downloads/php-7.2.2/Zend/zend.c:1105
#1 0x000000000093fb5b in div_function (result=0x7fffef61e090, op1=0x7fffe70e61c0, op2=0x7fffe70e61d0) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_operators.c:1173
#2 0x00000000009a82a0 in fast_div_function (result=0x7fffef61e090, op1=0x7fffe70e61c0, op2=0x7fffe70e61d0) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_operators.h:738
#3 0x00000000009b9f22 in ZEND_DIV_SPEC_CONST_CONST_HANDLER () at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:4251
#4 0x0000000000a381d4 in execute_ex (ex=0x7fffef61e030) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:59986
#5 0x0000000000a3d0ab in zend_execute (op_array=0x7fffef684300, return_value=0x0) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend_vm_execute.h:63760
#6 0x000000000094cd22 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/dinosaur/Downloads/php-7.2.2/Zend/zend.c:1496
#7 0x00000000008b0b4a in php_execute_script (primary_file=0x7fffffffca10) at /home/dinosaur/Downloads/php-7.2.2/main/main.c:2590
#8 0x0000000000a3fd23 in do_cli (argc=2, argv=0x1441f40) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1011
#9 0x0000000000a40ee0 in main (argc=2, argv=0x1441f40) at /home/dinosaur/Downloads/php-7.2.2/sapi/cli/php_cli.c:1404

zend_error 翻到最底下就是write 系统调用了

				if (Z_LVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
return SUCCESS;
}

zend_error后就return 了,所以后面的程序可以继续执行

对比总结

1/0 不会被抛出异常,会有warning 并继续执行 

坑点在于:

  • 不是所有的error都能被catch
  • 没有被catch 住的话会继续执行